Mercurial > code > home > repos > homeauto
diff espNode/component/cam.h @ 1740:c77b5ab7b99d
camera work
author | drewp@bigasterisk.com |
---|---|
date | Fri, 01 Sep 2023 17:13:51 -0700 |
parents | 82213d91471c |
children |
line wrap: on
line diff
--- a/espNode/component/cam.h Fri Sep 01 17:12:06 2023 -0700 +++ b/espNode/component/cam.h Fri Sep 01 17:13:51 2023 -0700 @@ -33,6 +33,17 @@ static const char *TAG = "cam"; +#define PART_BOUNDARY "123456789000000000000987654321" +static const char *_STREAM_CONTENT_TYPE = + "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; +static const char *_STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; +static const char *_STREAM_PART = + "Content-Type: image/jpeg\r\nContent-Length: %u\r\nX-Timestamp: " + "%d.%06d\r\n\r\n"; + +httpd_handle_t camera_httpd = NULL; +httpd_handle_t stream_httpd = NULL; + typedef struct { httpd_req_t *req; size_t len; @@ -66,7 +77,7 @@ config.pin_pwdn = PWDN_GPIO_NUM; config.pin_reset = RESET_GPIO_NUM; config.xclk_freq_hz = 20000000; - config.frame_size = FRAMESIZE_QVGA; + config.frame_size = FRAMESIZE_SVGA; config.pixel_format = PIXFORMAT_JPEG; // for streaming // config.pixel_format = PIXFORMAT_RGB565; // for face detection/recognition // config.grab_mode = CAMERA_GRAB_WHEN_EMPTY; @@ -84,6 +95,7 @@ esp_err_t err = esp_camera_init(&config); if (err != ESP_OK) { Serial.printf("Camera init failed with error 0x%x", err); + mark_failed(); return; } @@ -143,10 +155,90 @@ return res; } + static esp_err_t stream_handler(httpd_req_t *req) { + camera_fb_t *fb = NULL; + struct timeval _timestamp; + esp_err_t res = ESP_OK; + size_t _jpg_buf_len = 0; + uint8_t *_jpg_buf = NULL; + char *part_buf[128]; + + static int64_t last_frame = 0; + if (!last_frame) { + last_frame = esp_timer_get_time(); + } + + res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE); + if (res != ESP_OK) { + return res; + } + + while (true) { + fb = esp_camera_fb_get(); + if (!fb) { + ESP_LOGE(TAG, "Camera capture failed"); + res = ESP_FAIL; + } else { + _timestamp.tv_sec = fb->timestamp.tv_sec; + _timestamp.tv_usec = fb->timestamp.tv_usec; + if (fb->format != PIXFORMAT_JPEG) { + ESP_LOGI(TAG, "format was %d; sw convert to jpeg", fb->format); + bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len); + esp_camera_fb_return(fb); + fb = NULL; + if (!jpeg_converted) { + ESP_LOGE(TAG, "JPEG compression failed"); + res = ESP_FAIL; + } + } else { + _jpg_buf_len = fb->len; + _jpg_buf = fb->buf; + } + } + if (res == ESP_OK) { + res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, + strlen(_STREAM_BOUNDARY)); + } + if (res == ESP_OK) { + size_t hlen = + snprintf((char *)part_buf, 128, _STREAM_PART, _jpg_buf_len, + _timestamp.tv_sec, _timestamp.tv_usec); + res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); + } + if (res == ESP_OK) { + res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len); + } + if (fb) { + esp_camera_fb_return(fb); + fb = NULL; + _jpg_buf = NULL; + } else if (_jpg_buf) { + free(_jpg_buf); + _jpg_buf = NULL; + } + if (res != ESP_OK) { + ESP_LOGE(TAG, "send frame failed failed"); + break; + } + int64_t fr_end = esp_timer_get_time(); + + int64_t frame_time = fr_end - last_frame; + frame_time /= 1000; + uint32_t avg_frame_time = -1; + // ESP_LOGI(TAG, "MJPG: %uB %ums (%.1ffps), AVG: %ums (%.1ffps)" + // , + // (uint32_t)(_jpg_buf_len), (uint32_t)frame_time, + // 1000.0 / (uint32_t)frame_time, avg_frame_time, + // 1000.0 / avg_frame_time); + } + + return res; + } + void startCameraServer() { ESP_LOGD(TAG, "startCameraServer"); httpd_config_t config = HTTPD_DEFAULT_CONFIG(); - config.server_port = 8000; + config.server_port = 80; config.max_uri_handlers = 16; httpd_uri_t capture_uri = {.uri = "/capture", @@ -154,18 +246,16 @@ .handler = capture_handler, .user_ctx = NULL}; - // httpd_uri_t stream_uri = { - // .uri = "/stream", - // .method = HTTP_GET, - // .handler = stream_handler, - // .user_ctx = NULL - // }; + httpd_uri_t stream_uri = {.uri = "/stream", + .method = HTTP_GET, + .handler = stream_handler, + .user_ctx = NULL}; // ra_filter_init(&ra_filter, 20); ESP_LOGCONFIG(TAG, "startCameraServer2"); ESP_LOGI(TAG, "Starting web server on port: '%d'", config.server_port); - httpd_handle_t camera_httpd = NULL; + if (httpd_start(&camera_httpd, &config) == ESP_OK) { // httpd_register_uri_handler(camera_httpd, &index_uri); // httpd_register_uri_handler(camera_httpd, &cmd_uri); @@ -180,13 +270,12 @@ // httpd_register_uri_handler(camera_httpd, &win_uri); } - // config.server_port += 1; - // config.ctrl_port += 1; - // ESP_LOGI(TAG, "Starting stream server on port: '%d'", - // config.server_port); if (httpd_start(&stream_httpd, &config) == ESP_OK) - // { - // httpd_register_uri_handler(stream_httpd, &stream_uri); - // } + config.server_port += 1; + config.ctrl_port += 1; + ESP_LOGI(TAG, "Starting stream server on port: '%d'", config.server_port); + if (httpd_start(&stream_httpd, &config) == ESP_OK) { + httpd_register_uri_handler(stream_httpd, &stream_uri); + } } void loop() override {}