diff --git a/components/CameraManager/CameraManager/CameraManager.cpp b/components/CameraManager/CameraManager/CameraManager.cpp index affc57a..be07945 100644 --- a/components/CameraManager/CameraManager/CameraManager.cpp +++ b/components/CameraManager/CameraManager/CameraManager.cpp @@ -106,7 +106,7 @@ void CameraManager::setupCameraPinout() .pin_pclk = 13, // CAM_PIN_PCLK, // XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental) - .xclk_freq_hz = 16500000, + .xclk_freq_hz = 20000000, // 20000000, .ledc_timer = LEDC_TIMER_0, .ledc_channel = LEDC_CHANNEL_0, @@ -157,6 +157,7 @@ void CameraManager::setupBasicResolution() if (!esp_psram_is_initialized()) { ESP_LOGE(CAMERA_MANAGER_TAG, "PSRAM not initialized!"); + ESP_LOGD(CAMERA_MANAGER_TAG, "Setting fb_location to CAMERA_FB_IN_DRAM with lower picture quality"); config.fb_location = CAMERA_FB_IN_DRAM; config.jpeg_quality = 9; config.fb_count = 2; @@ -166,8 +167,6 @@ void CameraManager::setupBasicResolution() { ESP_LOGE(CAMERA_MANAGER_TAG, "PSRAM size: %u", esp_psram_get_size()); } - - ESP_LOGD(CAMERA_MANAGER_TAG, "Setting fb_location to CAMERA_FB_IN_PSRAM"); } void CameraManager::setupCameraSensor() @@ -229,6 +228,8 @@ void CameraManager::setupCameraSensor() 2); // 0 to 6 (0 - No Effect, 1 - Negative, 2 - Grayscale, 3 - Red Tint, // 4 - Green Tint, 5 - Blue Tint, 6 - Sepia) + // it gets overriden somewhere somehow + camera_sensor->set_framesize(camera_sensor, FRAMESIZE_240X240); ESP_LOGI(CAMERA_MANAGER_TAG, "Setting up camera sensor done"); } @@ -280,7 +281,7 @@ bool CameraManager::setupCamera() } #endif - // this->setupCameraSensor(); + this->setupCameraSensor(); // this->loadConfigData(); // move this to update method once implemented return true; } diff --git a/components/StreamServer/CMakeLists.txt b/components/StreamServer/CMakeLists.txt new file mode 100644 index 0000000..02e35bb --- /dev/null +++ b/components/StreamServer/CMakeLists.txt @@ -0,0 +1,4 @@ +idf_component_register(SRCS "StreamServer/StreamServer.cpp" + INCLUDE_DIRS "StreamServer" + REQUIRES esp32-camera StateManager ProjectConfig esp_http_server Helpers +) \ No newline at end of file diff --git a/components/StreamServer/StreamServer/StreamServer.cpp b/components/StreamServer/StreamServer/StreamServer.cpp new file mode 100644 index 0000000..bf8383a --- /dev/null +++ b/components/StreamServer/StreamServer/StreamServer.cpp @@ -0,0 +1,115 @@ +#include "StreamServer.hpp" + +constexpr static const char *STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY; +constexpr static const char *STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n"; +constexpr static const char *STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\nX-Timestamp: %lli.%06li\r\n\r\n"; + +static const char *STREAM_SERVER_TAG = "[STREAM_SERVER]"; + +// the stream is super low FPS, find out why +esp_err_t StreamHelpers::stream(httpd_req_t *req) +{ + long last_request_time = 0; + camera_fb_t *fb = nullptr; + struct timeval _timestamp; + + esp_err_t response = ESP_OK; + size_t _jpg_buf_len = 0; + uint8_t *_jpg_buf = nullptr; + + char *part_buf[256]; + static int64_t last_frame = 0; + if (!last_frame) + last_frame = esp_timer_get_time(); + + response = httpd_resp_set_type(req, STREAM_CONTENT_TYPE); + if (response != ESP_OK) + return response; + + httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); + httpd_resp_set_hdr(req, "X-Framerate", "60"); + + while (true) + { + fb = esp_camera_fb_get(); + + if (!fb) + { + ESP_LOGE(STREAM_SERVER_TAG, "Camera capture failed with resposne %s", esp_err_to_name(response)); + response = ESP_FAIL; + } + else + { + _timestamp.tv_sec = fb->timestamp.tv_sec; + _timestamp.tv_usec = fb->timestamp.tv_usec; + _jpg_buf_len = fb->len; + _jpg_buf = fb->buf; + } + if (response == ESP_OK) + response = httpd_resp_send_chunk(req, STREAM_BOUNDARY, strlen(STREAM_BOUNDARY)); + if (response == ESP_OK) + { + size_t hlen = snprintf((char *)part_buf, 128, STREAM_PART, _jpg_buf_len, _timestamp.tv_sec, _timestamp.tv_usec); + response = httpd_resp_send_chunk(req, (const char *)part_buf, hlen); + } + if (response == ESP_OK) + response = 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 (response != ESP_OK) + break; + long request_end = Helpers::getTimeInMillis(); + long latency = (request_end - last_request_time); + last_request_time = request_end; + ESP_LOGD(STREAM_SERVER_TAG, "Size: %uKB, Time: %lims (%lifps)\n", _jpg_buf_len / 1024, latency, 1000 / latency); + } + last_frame = 0; + return response; +} + +StreamServer::StreamServer(const int STREAM_PORT) : STREAM_SERVER_PORT(STREAM_PORT) {} + +esp_err_t StreamServer::startStreamServer() +{ + if (cameraStateManager.getCurrentState() != CameraState_e::Camera_Success) + { + ESP_LOGE(STREAM_SERVER_TAG, "Camera not initialized. Cannot start stream server."); + return ESP_FAIL; + } + + httpd_config_t config = HTTPD_DEFAULT_CONFIG(); + config.stack_size = 20480; + config.max_uri_handlers = 1; + config.server_port = STREAM_SERVER_PORT; + config.ctrl_port = STREAM_SERVER_PORT; + + httpd_uri_t stream_page = { + .uri = "/", + .method = HTTP_GET, + .handler = &StreamHelpers::stream, + .user_ctx = nullptr, + }; + + int status = httpd_start(&camera_stream, &config); + + if (status != ESP_OK) + { + ESP_LOGE(STREAM_SERVER_TAG, "Cannot start stream server."); + return status; + } + + httpd_register_uri_handler(camera_stream, &stream_page); + ESP_LOGI(STREAM_SERVER_TAG, "Stream server started on port %d", STREAM_SERVER_PORT); + // todo add printing IP addr here + + return ESP_OK; +} \ No newline at end of file diff --git a/components/StreamServer/StreamServer/StreamServer.hpp b/components/StreamServer/StreamServer/StreamServer.hpp new file mode 100644 index 0000000..ae584be --- /dev/null +++ b/components/StreamServer/StreamServer/StreamServer.hpp @@ -0,0 +1,30 @@ +#pragma once +#ifndef STREAMSERVER_HPP +#define STREAMSERVER_HPP + +#define PART_BOUNDARY "123456789000000000000987654321" + +#include "esp_log.h" +#include "esp_camera.h" +#include "esp_http_server.h" +#include "esp_timer.h" +#include +#include + +namespace StreamHelpers +{ + esp_err_t stream(httpd_req_t *req); +} + +class StreamServer +{ +private: + httpd_handle_t camera_stream = nullptr; + int STREAM_SERVER_PORT; + +public: + StreamServer(const int STREAM_PORT = 80); + esp_err_t startStreamServer(); +}; + +#endif \ No newline at end of file diff --git a/main/Kconfig.projbuild b/main/Kconfig.projbuild index e4634dd..87d3dc8 100644 --- a/main/Kconfig.projbuild +++ b/main/Kconfig.projbuild @@ -46,6 +46,10 @@ menu "OpenIris basic configuration" help Define the blinking period in milliseconds. + config WIRED_MODE + bool "WIred mode" + default false + config WIFI_SSID string "WiFi network name" default "" diff --git a/main/openiris_main.cpp b/main/openiris_main.cpp index 0666721..9025239 100644 --- a/main/openiris_main.cpp +++ b/main/openiris_main.cpp @@ -16,6 +16,7 @@ #include #include #include +#include #define BLINK_GPIO (gpio_num_t) CONFIG_BLINK_GPIO @@ -57,6 +58,7 @@ extern "C" void app_main(void) WiFiManager wifiManager; MDNSManager mdnsManager(deviceConfig); CameraManager cameraHandler(deviceConfig); + StreamServer streamServer; #ifdef CONFIG_USE_ILLUMNATIOR_PIN // LEDManager ledManager(BLINK_GPIO, ILLUMINATOR_PIN); @@ -73,29 +75,12 @@ extern "C" void app_main(void) wifiManager.Begin(); mdnsManager.start(); cameraHandler.setupCamera(); + streamServer.startStreamServer(); while (1) { ledManager.handleLED(); - ESP_LOGI(TAG, "Free heap: %u, free PSRAM: %u", esp_get_free_heap_size(), esp_get_free_internal_heap_size()); - heap_caps_print_heap_info(MALLOC_CAP_SPIRAM); - - if (cameraStateManager.getCurrentState() != CameraState_e::Camera_Success) - return; - - ESP_LOGI(TAG, "Taking picture..."); - camera_fb_t *pic = esp_camera_fb_get(); - - // use pic->buf to access the image - if (pic == NULL) - { - ESP_LOGE(TAG, "Camera capture failed"); - continue; - } - - ESP_LOGI(TAG, "Picture taken! Its size was: %zu bytes", pic->len); - esp_camera_fb_return(pic); vTaskDelay(CONFIG_BLINK_PERIOD / portTICK_PERIOD_MS); } } diff --git a/sdkconfig b/sdkconfig index 3c38ae3..22e34fd 100644 --- a/sdkconfig +++ b/sdkconfig @@ -539,6 +539,7 @@ CONFIG_BLINK_LED_GPIO=y # CONFIG_BLINK_LED_STRIP is not set CONFIG_BLINK_GPIO=21 CONFIG_BLINK_PERIOD=1000 +# CONFIG_WIRED_MODE is not set CONFIG_WIFI_SSID="UPC7878684" CONFIG_WIFI_PASSOWRD="j3ttQPpfvhep" # end of OpenIris basic configuration