21 #include "../../include/esp3d_config.h"
24 #include "../../core/settings_esp3d.h"
25 #include "../network/netservices.h"
26 #include "../../core/esp3doutput.h"
27 #include "../network/netconfig.h"
28 #include "esp_http_server.h"
29 #include <esp_camera.h>
30 #include "fd_forward.h"
32 #include <soc/rtc_cntl_reg.h>
33 #include <driver/i2c.h>
35 #define DEFAULT_FRAME_SIZE FRAMESIZE_SVGA
36 #define HTTP_TASK_PRIORITY 5
37 #define PART_BUFFER_SIZE 64
38 #define JPEG_COMPRESSION 80
39 #define MIN_WIDTH_COMPRESSION 400
40 #define PART_BOUNDARY "123456789000000000000987654321"
41 static const char* _STREAM_CONTENT_TYPE =
"multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
42 static const char* _STREAM_BOUNDARY =
"\r\n--" PART_BOUNDARY
"\r\n";
43 static const char* _STREAM_PART =
"Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
45 httpd_handle_t stream_httpd = NULL;
49 static void disconnected_uri(httpd_handle_t hd,
int sockfd)
55 static esp_err_t stream_handler(httpd_req_t *req)
59 const char* resp =
"Camera not started";
61 httpd_resp_send(req, resp, strlen(resp));
65 #ifdef ESP_ACCESS_CONTROL_ALLOW_ORIGIN
66 httpd_resp_set_hdr(req,
"Access-Control-Allow-Origin",
"*");
67 #endif //ESP_ACCESS_CONTROL_ALLOw_ORIGIN
68 camera_fb_t * fb = NULL;
69 esp_err_t res = ESP_OK;
70 size_t _jpg_buf_len = 0;
71 uint8_t * _jpg_buf = NULL;
72 char * part_buf[PART_BUFFER_SIZE];
73 dl_matrix3du_t *image_matrix = NULL;
74 res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
77 const char* resp =
"Stream type failed";
79 httpd_resp_send(req, resp, strlen(resp));
85 const char* resp =
"Camera is not connected";
87 httpd_resp_send(req, resp, strlen(resp));
91 fb = esp_camera_fb_get();
102 if(fb->width > MIN_WIDTH_COMPRESSION) {
103 if(fb->format != PIXFORMAT_JPEG) {
104 bool jpeg_converted = frame2jpg(fb, JPEG_COMPRESSION, &_jpg_buf, &_jpg_buf_len);
105 esp_camera_fb_return(fb);
107 if(!jpeg_converted) {
112 _jpg_buf_len = fb->len;
116 image_matrix = dl_matrix3du_alloc(1, fb->width, fb->height, 3);
122 if(!fmt2rgb888(fb->buf, fb->len, fb->format, image_matrix->item)) {
126 if (fb->format != PIXFORMAT_JPEG) {
127 if(!fmt2jpg(image_matrix->item, fb->width*fb->height*3, fb->width, fb->height, PIXFORMAT_RGB888, 90, &_jpg_buf, &_jpg_buf_len)) {
131 esp_camera_fb_return(fb);
135 _jpg_buf_len = fb->len;
138 dl_matrix3du_free(image_matrix);
144 size_t hlen = snprintf((
char *)part_buf, PART_BUFFER_SIZE, _STREAM_PART, _jpg_buf_len);
145 res = httpd_resp_send_chunk(req, (
const char *)part_buf, hlen);
148 res = httpd_resp_send_chunk(req, (
const char *)_jpg_buf, _jpg_buf_len);
151 res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
154 esp_camera_fb_return(fb);
157 }
else if(_jpg_buf) {
172 _initialised =
false;
185 int val = atoi(value);
186 sensor_t * s = esp_camera_sensor_get();
190 #if CAM_LED_PIN != -1
191 if (!strcmp(param,
"light")) {
195 if(!strcmp(param,
"framesize")) {
196 if(s->pixformat == PIXFORMAT_JPEG) {
197 res = s->set_framesize(s, (framesize_t)val);
199 }
else if(!strcmp(param,
"quality")) {
200 res = s->set_quality(s, val);
201 }
else if(!strcmp(param,
"contrast")) {
202 res = s->set_contrast(s, val);
203 }
else if(!strcmp(param,
"brightness")) {
204 res = s->set_brightness(s, val);
205 }
else if(!strcmp(param,
"saturation")) {
206 res = s->set_saturation(s, val);
207 }
else if(!strcmp(param,
"gainceiling")) {
208 res = s->set_gainceiling(s, (gainceiling_t)val);
209 }
else if(!strcmp(param,
"colorbar")) {
210 res = s->set_colorbar(s, val);
211 }
else if(!strcmp(param,
"awb")) {
212 res = s->set_whitebal(s, val);
213 }
else if(!strcmp(param,
"agc")) {
214 res = s->set_gain_ctrl(s, val);
215 }
else if(!strcmp(param,
"aec")) {
216 res = s->set_exposure_ctrl(s, val);
217 }
else if(!strcmp(param,
"hmirror")) {
218 res = s->set_hmirror(s, val);
219 }
else if(!strcmp(param,
"vflip")) {
220 res = s->set_vflip(s, val);
221 }
else if(!strcmp(param,
"awb_gain")) {
222 res = s->set_awb_gain(s, val);
223 }
else if(!strcmp(param,
"agc_gain")) {
224 res = s->set_agc_gain(s, val);
225 }
else if(!strcmp(param,
"aec_value")) {
226 res = s->set_aec_value(s, val);
227 }
else if(!strcmp(param,
"aec2")) {
228 res = s->set_aec2(s, val);
229 }
else if(!strcmp(param,
"dcw")) {
230 res = s->set_dcw(s, val);
231 }
else if(!strcmp(param,
"bpc")) {
232 res = s->set_bpc(s, val);
233 }
else if(!strcmp(param,
"wpc")) {
234 res = s->set_wpc(s, val);
235 }
else if(!strcmp(param,
"raw_gma")) {
236 res = s->set_raw_gma(s, val);
237 }
else if(!strcmp(param,
"lenc")) {
238 res = s->set_lenc(s, val);
239 }
else if(!strcmp(param,
"special_effect")) {
240 res = s->set_special_effect(s, val);
241 }
else if(!strcmp(param,
"wb_mode")) {
242 res = s->set_wb_mode(s, val);
243 }
else if(!strcmp(param,
"ae_level")) {
244 res = s->set_ae_level(s, val);
254 _initialised =
false;
260 WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
261 camera_config_t config;
262 config.ledc_channel = LEDC_CHANNEL_0;
263 config.ledc_timer = LEDC_TIMER_0;
280 config.xclk_freq_hz = 10000000;
281 config.pixel_format = PIXFORMAT_JPEG;
282 config.jpeg_quality = 5;
284 config.frame_size = DEFAULT_FRAME_SIZE;
286 _initialised =
false;
294 #if CAM_PULLUP1 != -1
297 #if CAM_PULLUP2 != -1
300 #if CAM_LED_PIN != -1
307 #if CAMERA_DEVICE == CAMERA_MODEL_AI_THINKER
308 log_esp3d(
"Specific config for CAMERA_MODEL_AI_THINKER");
309 gpio_config_t gpio_pwr_config;
310 gpio_pwr_config.pin_bit_mask = (1ULL << 32);
311 gpio_pwr_config.mode = GPIO_MODE_OUTPUT;
312 gpio_pwr_config.pull_down_en = GPIO_PULLDOWN_DISABLE;
313 gpio_pwr_config.pull_up_en = GPIO_PULLUP_DISABLE;
314 gpio_pwr_config.intr_type = GPIO_INTR_DISABLE;
315 gpio_config(&gpio_pwr_config);
316 gpio_set_level(GPIO_NUM_32,0);
317 #endif //CAMERA_DEVICE == CAMERA_MODEL_AI_THINKER
319 esp_err_t err = esp_camera_init(&config);
321 log_esp3d(
"Camera init failed with error 0x%x", err);
322 _initialised =
false;
332 _initialised =
false;
334 esp_err_t err = esp_camera_deinit();
337 if(i2c_driver_delete(I2C_NUM_1)!= ESP_OK) {
342 log_esp3d(
"Camera deinit failed with error 0x%x", err);
357 log_esp3d(
"Init camera sensor settings");
358 sensor_t * s = esp_camera_sensor_get();
361 if (s->id.PID == OV3660_PID) {
362 s->set_brightness(s, 1);
363 s->set_saturation(s, -2);
366 s->set_framesize(s, DEFAULT_FRAME_SIZE);
368 #if defined(CAMERA_DEVICE_FLIP_HORIZONTALY)
369 s->set_hmirror(s, 1);
370 #endif //CAMERA_DEVICE_FLIP_HORIZONTALY
371 #if defined(CAMERA_DEVICE_FLIP_VERTICALY)
373 #endif //CAMERA_DEVICE_FLIP_VERTICALY
375 log_esp3d(
"Cannot access camera sensor");
379 httpd_config_t httpdconfig = HTTPD_DEFAULT_CONFIG();
380 httpdconfig.close_fn =&disconnected_uri;
381 httpd_uri_t stream_uri = {
384 .handler = stream_handler,
388 httpdconfig.server_port = _port;
389 httpdconfig.ctrl_port = httpdconfig.server_port +1;
390 httpdconfig.task_priority = HTTP_TASK_PRIORITY;
392 if (httpd_start(&stream_httpd, &httpdconfig) == ESP_OK) {
393 String stmp =
"Camera server started port " + String(httpdconfig.server_port);
394 output.printMSG(stmp.c_str());
396 if (httpd_register_uri_handler(stream_httpd, &stream_uri) != ESP_OK) {
400 log_esp3d(
"Starting camera server failed");
401 output.printERROR(
"Starting camera server failed");
406 for (
int j = 0; j < 5; j++) {
407 camera_fb_t * fb = esp_camera_fb_get();
411 esp_camera_fb_return(fb);
423 if (ESP_OK != httpd_unregister_uri(stream_httpd,
"/stream")) {
424 log_esp3d(
"Error unregistering /stream");
427 if (ESP_OK != httpd_stop(stream_httpd)) {
428 log_esp3d(
"Error stopping stream server");
440 return CAMERA_DEVICE;
445 #if defined(CUSTOM_CAMERA_NAME)
448 switch(CAMERA_DEVICE) {
456 return "M5Stack with PSRam";
459 return "M5Stack wide";
465 return "Unknow Camera";
467 #endif //CUSTOM_CAMERA_NAME
469 #endif //CAMERA_DEVICE