diff --git a/app_httpd.cpp b/app_httpd.cpp index 5b4c8bd..8280983 100644 --- a/app_httpd.cpp +++ b/app_httpd.cpp @@ -52,6 +52,7 @@ extern int8_t streamCount; extern unsigned long streamsServed; extern unsigned long imagesServed; extern int myRotation; +extern int framerateLimit; extern int lampVal; extern bool autoLamp; extern bool filesystem; @@ -274,13 +275,16 @@ static esp_err_t stream_handler(httpd_req_t *req){ break; } int64_t frame_time = esp_timer_get_time() - last_frame; - last_frame = esp_timer_get_time();; frame_time /= 1000; + int32_t frame_delay = (framerateLimit > frame_time) ? framerateLimit - frame_time : 0; + delay(frame_delay); + if (debugData) { - Serial.printf("MJPG: %uB %ums (%.1ffps)\r\n", + Serial.printf("MJPG: %uB %ums, delay: %ums, framerate (%.1ffps)\r\n", (uint32_t)(_jpg_buf_len), - (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time); + (uint32_t)frame_time, frame_delay, 1000.0 / (uint32_t)(frame_time + frame_delay)); } + last_frame = esp_timer_get_time(); } streamsServed++; @@ -355,6 +359,7 @@ static esp_err_t cmd_handler(httpd_req_t *req){ else if(!strcmp(variable, "wb_mode")) res = s->set_wb_mode(s, val); else if(!strcmp(variable, "ae_level")) res = s->set_ae_level(s, val); else if(!strcmp(variable, "rotate")) myRotation = val; + else if(!strcmp(variable, "framerate_limit")) framerateLimit = val; else if(!strcmp(variable, "autolamp") && (lampVal != -1)) { autoLamp = val; if (autoLamp) { @@ -410,6 +415,7 @@ static esp_err_t status_handler(httpd_req_t *req){ *p++ = '{'; p+=sprintf(p, "\"lamp\":%d,", lampVal); p+=sprintf(p, "\"autolamp\":%d,", autoLamp); + p+=sprintf(p, "\"framerate_limit\":%d,", framerateLimit); p+=sprintf(p, "\"framesize\":%u,", s->status.framesize); p+=sprintf(p, "\"quality\":%u,", s->status.quality); p+=sprintf(p, "\"brightness\":%d,", s->status.brightness); diff --git a/esp32-cam-webserver.ino b/esp32-cam-webserver.ino index 507030d..50a5dc2 100644 --- a/esp32-cam-webserver.ino +++ b/esp32-cam-webserver.ino @@ -147,6 +147,12 @@ char myVer[] PROGMEM = __DATE__ " @ " __TIME__; #endif int myRotation = CAM_ROTATION; +// minimal frame duration in ms, effectively 1/maxFPS +#if !defined(FRAMERATE_LIMIT) + #define FRAMERATE_LIMIT 0 +#endif +int framerateLimit = FRAMERATE_LIMIT; + // Illumination LAMP and status LED #if defined(LAMP_DISABLE) int lampVal = -1; // lamp is disabled in config diff --git a/myconfig.sample.h b/myconfig.sample.h index 215f9ec..f40dcdb 100644 --- a/myconfig.sample.h +++ b/myconfig.sample.h @@ -143,6 +143,9 @@ struct station stationList[] = {{"ssid1", "pass1", true}, // Browser Rotation (one of: -90,0,90, default 0) // #define CAM_ROTATION 0 +// Minimal frame duration in ms, used to limit max FPS +// max_fps = 1000/framerate_limit +// #define FRAMERATE_LIMIT 500 /* * Additional Features diff --git a/storage.cpp b/storage.cpp index 8ebc7fa..c463c97 100644 --- a/storage.cpp +++ b/storage.cpp @@ -7,6 +7,7 @@ extern void flashLED(int flashtime); extern int myRotation; // Rotation extern int lampVal; // The current Lamp value extern int autoLamp; // Automatic lamp mode +extern int framerateLimit; // Minimal frame duration /* * Useful utility when debugging... @@ -90,6 +91,7 @@ void loadPrefs(fs::FS &fs){ // process all the settings lampVal = jsonExtract(prefs, "lamp").toInt(); autoLamp = jsonExtract(prefs, "autolamp").toInt(); + framerateLimit = jsonExtract(prefs, "framerate_limit").toInt(); s->set_framesize(s, (framesize_t)jsonExtract(prefs, "framesize").toInt()); s->set_quality(s, jsonExtract(prefs, "quality").toInt()); s->set_brightness(s, jsonExtract(prefs, "brightness").toInt()); @@ -136,6 +138,7 @@ void savePrefs(fs::FS &fs){ *p++ = '{'; p+=sprintf(p, "\"lamp\":%i,", lampVal); p+=sprintf(p, "\"autolamp\":%u,", autoLamp); + p+=sprintf(p, "\"framerate_limit\":%d,", framerateLimit); p+=sprintf(p, "\"framesize\":%u,", s->status.framesize); p+=sprintf(p, "\"quality\":%u,", s->status.quality); p+=sprintf(p, "\"brightness\":%d,", s->status.brightness);