to_jpg.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. // Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stddef.h>
  15. #include <string.h>
  16. #include "esp_attr.h"
  17. #include "soc/efuse_reg.h"
  18. #include "esp_heap_caps.h"
  19. #include <esp_camera.h>
  20. #include "img_converters.h"
  21. #include "jpge.h"
  22. #include "yuv.h"
  23. #include "esp_system.h"
  24. #if ESP_IDF_VERSION_MAJOR >= 4 // IDF 4+
  25. #if CONFIG_IDF_TARGET_ESP32 // ESP32/PICO-D4
  26. #include "esp32/spiram.h"
  27. #else
  28. #error Target CONFIG_IDF_TARGET is not supported
  29. #endif
  30. #else // ESP32 Before IDF 4.0
  31. #include "esp_spiram.h"
  32. #endif
  33. #if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
  34. #include "esp32-hal-log.h"
  35. #define TAG ""
  36. #else
  37. #include "esp_log.h"
  38. static const char* TAG = "to_jpg";
  39. #endif
  40. static void *_malloc(size_t size)
  41. {
  42. void * res = malloc(size);
  43. if(res) {
  44. return res;
  45. }
  46. return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
  47. }
  48. static IRAM_ATTR void convert_line_format(uint8_t * src, pixformat_t format, uint8_t * dst, size_t width, size_t in_channels, size_t line)
  49. {
  50. int i=0, o=0, l=0;
  51. if(format == PIXFORMAT_GRAYSCALE) {
  52. memcpy(dst, src + line * width, width);
  53. } else if(format == PIXFORMAT_RGB888) {
  54. l = width * 3;
  55. src += l * line;
  56. for(i=0; i<l; i+=3) {
  57. dst[o++] = src[i+2];
  58. dst[o++] = src[i+1];
  59. dst[o++] = src[i];
  60. }
  61. } else if(format == PIXFORMAT_RGB565) {
  62. l = width * 2;
  63. src += l * line;
  64. for(i=0; i<l; i+=2) {
  65. dst[o++] = src[i] & 0xF8;
  66. dst[o++] = (src[i] & 0x07) << 5 | (src[i+1] & 0xE0) >> 3;
  67. dst[o++] = (src[i+1] & 0x1F) << 3;
  68. }
  69. } else if(format == PIXFORMAT_YUV422) {
  70. uint8_t y0, y1, u, v;
  71. uint8_t r, g, b;
  72. l = width * 2;
  73. src += l * line;
  74. for(i=0; i<l; i+=4) {
  75. y0 = src[i];
  76. u = src[i+1];
  77. y1 = src[i+2];
  78. v = src[i+3];
  79. yuv2rgb(y0, u, v, &r, &g, &b);
  80. dst[o++] = r;
  81. dst[o++] = g;
  82. dst[o++] = b;
  83. yuv2rgb(y1, u, v, &r, &g, &b);
  84. dst[o++] = r;
  85. dst[o++] = g;
  86. dst[o++] = b;
  87. }
  88. }
  89. }
  90. bool convert_image(uint8_t *src, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpge::output_stream *dst_stream)
  91. {
  92. int num_channels = 3;
  93. jpge::subsampling_t subsampling = jpge::H2V2;
  94. if(format == PIXFORMAT_GRAYSCALE) {
  95. num_channels = 1;
  96. subsampling = jpge::Y_ONLY;
  97. }
  98. if(!quality) {
  99. quality = 1;
  100. } else if(quality > 100) {
  101. quality = 100;
  102. }
  103. jpge::params comp_params = jpge::params();
  104. comp_params.m_subsampling = subsampling;
  105. comp_params.m_quality = quality;
  106. jpge::jpeg_encoder dst_image;
  107. if (!dst_image.init(dst_stream, width, height, num_channels, comp_params)) {
  108. ESP_LOGE(TAG, "JPG encoder init failed");
  109. return false;
  110. }
  111. uint8_t* line = (uint8_t*)_malloc(width * num_channels);
  112. if(!line) {
  113. ESP_LOGE(TAG, "Scan line malloc failed");
  114. return false;
  115. }
  116. for (int i = 0; i < height; i++) {
  117. convert_line_format(src, format, line, width, num_channels, i);
  118. if (!dst_image.process_scanline(line)) {
  119. ESP_LOGE(TAG, "JPG process line %u failed", i);
  120. free(line);
  121. return false;
  122. }
  123. }
  124. free(line);
  125. if (!dst_image.process_scanline(NULL)) {
  126. ESP_LOGE(TAG, "JPG image finish failed");
  127. return false;
  128. }
  129. dst_image.deinit();
  130. return true;
  131. }
  132. class callback_stream : public jpge::output_stream {
  133. protected:
  134. jpg_out_cb ocb;
  135. void * oarg;
  136. size_t index;
  137. public:
  138. callback_stream(jpg_out_cb cb, void * arg) : ocb(cb), oarg(arg), index(0) { }
  139. virtual ~callback_stream() { }
  140. virtual bool put_buf(const void* data, int len)
  141. {
  142. index += ocb(oarg, index, data, len);
  143. return true;
  144. }
  145. virtual size_t get_size() const
  146. {
  147. return index;
  148. }
  149. };
  150. bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void * arg)
  151. {
  152. callback_stream dst_stream(cb, arg);
  153. return convert_image(src, width, height, format, quality, &dst_stream);
  154. }
  155. bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg)
  156. {
  157. return fmt2jpg_cb(fb->buf, fb->len, fb->width, fb->height, fb->format, quality, cb, arg);
  158. }
  159. class memory_stream : public jpge::output_stream {
  160. protected:
  161. uint8_t *out_buf;
  162. size_t max_len, index;
  163. public:
  164. memory_stream(void *pBuf, uint buf_size) : out_buf(static_cast<uint8_t*>(pBuf)), max_len(buf_size), index(0) { }
  165. virtual ~memory_stream() { }
  166. virtual bool put_buf(const void* pBuf, int len)
  167. {
  168. if (!pBuf) {
  169. //end of image
  170. return true;
  171. }
  172. if ((size_t)len > (max_len - index)) {
  173. ESP_LOGW(TAG, "JPG output overflow: %d bytes", len - (max_len - index));
  174. len = max_len - index;
  175. }
  176. if (len) {
  177. memcpy(out_buf + index, pBuf, len);
  178. index += len;
  179. }
  180. return true;
  181. }
  182. virtual size_t get_size() const
  183. {
  184. return index;
  185. }
  186. };
  187. bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t ** out, size_t * out_len)
  188. {
  189. //todo: allocate proper buffer for holding JPEG data
  190. //this should be enough for CIF frame size
  191. // int jpg_buf_len = 64*1024;
  192. int jpg_buf_len = 256*1024; // Anpassung wg. zu kleiner Bitmaps
  193. uint8_t * jpg_buf = (uint8_t *)_malloc(jpg_buf_len);
  194. if(jpg_buf == NULL) {
  195. ESP_LOGE(TAG, "JPG buffer malloc failed");
  196. return false;
  197. }
  198. memory_stream dst_stream(jpg_buf, jpg_buf_len);
  199. if(!convert_image(src, width, height, format, quality, &dst_stream)) {
  200. free(jpg_buf);
  201. return false;
  202. }
  203. *out = jpg_buf;
  204. *out_len = dst_stream.get_size();
  205. return true;
  206. }
  207. bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len)
  208. {
  209. return fmt2jpg(fb->buf, fb->len, fb->width, fb->height, fb->format, quality, out, out_len);
  210. }