Add Webcam commands

This commit is contained in:
Theo Arends 2020-05-08 17:17:09 +02:00
parent 0572644c7f
commit f66a0ee561
2 changed files with 157 additions and 54 deletions

View File

@ -182,6 +182,35 @@ typedef union {
}; };
} Timer; } Timer;
typedef union { // Restricted by MISRA-C Rule 18.4 but so useful...
uint32_t data;
struct {
uint32_t stream : 1;
uint32_t mirror : 1;
uint32_t flip : 1;
uint32_t spare3 : 1;
uint32_t spare4 : 1;
uint32_t spare5 : 1;
uint32_t spare6 : 1;
uint32_t spare7 : 1;
uint32_t spare8 : 1;
uint32_t spare9 : 1;
uint32_t spare10 : 1;
uint32_t spare11 : 1;
uint32_t spare12 : 1;
uint32_t spare13 : 1;
uint32_t spare14 : 1;
uint32_t spare15 : 1;
uint32_t spare16 : 1;
uint32_t spare17 : 1;
uint32_t spare18 : 1;
uint32_t contrast : 3;
uint32_t brightness : 3;
uint32_t saturation : 3;
uint32_t resolution : 4;
};
} WebCamCfg;
typedef union { typedef union {
uint16_t data; uint16_t data;
struct { struct {
@ -365,9 +394,11 @@ struct {
myio my_gp; // 3AC - 2 x 40 bytes (ESP32) myio my_gp; // 3AC - 2 x 40 bytes (ESP32)
mytmplt user_template; // 3FC - 2 x 37 bytes (ESP32) mytmplt user_template; // 3FC - 2 x 37 bytes (ESP32)
uint8_t free_esp32_446[10]; // 446 uint8_t free_esp32_446[6]; // 446
uint8_t esp32_webcam_resolution; // 450 WebCamCfg webcam_config; // 44C
uint8_t free_esp32_450[1]; // 450
#endif // ESP8266 - ESP32 #endif // ESP8266 - ESP32
char serial_delimiter; // 451 char serial_delimiter; // 451

View File

@ -230,11 +230,19 @@ uint32_t wc_setup(int32_t fsiz) {
sensor_t * wc_s = esp_camera_sensor_get(); sensor_t * wc_s = esp_camera_sensor_get();
// initial sensors are flipped vertically and colors are a bit saturated // initial sensors are flipped vertically and colors are a bit saturated
/*
if (OV3660_PID == wc_s->id.PID) { if (OV3660_PID == wc_s->id.PID) {
wc_s->set_vflip(wc_s, 1); // flip it back wc_s->set_vflip(wc_s, 1); // flip it back
wc_s->set_brightness(wc_s, 1); // up the brightness just a bit wc_s->set_brightness(wc_s, 1); // up the brightness just a bit
wc_s->set_saturation(wc_s, -2); // lower the saturation wc_s->set_saturation(wc_s, -2); // lower the saturation
} }
*/
wc_s->set_vflip(wc_s, Settings.webcam_config.flip);
wc_s->set_hmirror(wc_s, Settings.webcam_config.mirror);
wc_s->set_brightness(wc_s, Settings.webcam_config.brightness -2); // up the brightness just a bit
wc_s->set_saturation(wc_s, Settings.webcam_config.saturation -2); // lower the saturation
wc_s->set_contrast(wc_s, Settings.webcam_config.contrast -2); // keep contrast
// drop down frame size for higher initial frame rate // drop down frame size for higher initial frame rate
wc_s->set_framesize(wc_s, (framesize_t)fsiz); wc_s->set_framesize(wc_s, (framesize_t)fsiz);
@ -243,7 +251,6 @@ uint32_t wc_setup(int32_t fsiz) {
wc_height = wc_fb->height; wc_height = wc_fb->height;
esp_camera_fb_return(wc_fb); esp_camera_fb_return(wc_fb);
#ifdef USE_FACE_DETECT #ifdef USE_FACE_DETECT
fd_init(); fd_init();
#endif #endif
@ -461,11 +468,11 @@ WiFiClient client;
void handleMjpeg(void) { void handleMjpeg(void) {
AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Handle camserver")); AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Handle camserver"));
//if (!wc_stream_active) { if (!wc_stream_active) {
wc_stream_active = 1; wc_stream_active = 1;
client = CamServer->client(); client = CamServer->client();
AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Create client")); AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Create client"));
//} }
} }
#ifdef USE_FACE_DETECT #ifdef USE_FACE_DETECT
@ -613,11 +620,9 @@ void handleMjpeg_task(void) {
bool jpeg_converted = false; bool jpeg_converted = false;
if (!client.connected()) { if (!client.connected()) {
wc_stream_active = 0;
AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Client fail")); AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Client fail"));
goto exit; wc_stream_active = 0;
} }
if (1 == wc_stream_active) { if (1 == wc_stream_active) {
client.flush(); client.flush();
client.setTimeout(3); client.setTimeout(3);
@ -626,15 +631,15 @@ void handleMjpeg_task(void) {
"Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n" "Content-Type: multipart/x-mixed-replace;boundary=" BOUNDARY "\r\n"
"\r\n"); "\r\n");
wc_stream_active = 2; wc_stream_active = 2;
} else { }
if (2 == wc_stream_active) {
wc_fb = esp_camera_fb_get(); wc_fb = esp_camera_fb_get();
if (!wc_fb) { if (!wc_fb) {
wc_stream_active = 0;
AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Frame fail")); AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Frame fail"));
goto exit; wc_stream_active = 0;
} }
}
if (2 == wc_stream_active) {
if (wc_fb->format != PIXFORMAT_JPEG) { if (wc_fb->format != PIXFORMAT_JPEG) {
jpeg_converted = frame2jpg(wc_fb, 80, &_jpg_buf, &_jpg_buf_len); jpeg_converted = frame2jpg(wc_fb, 80, &_jpg_buf, &_jpg_buf_len);
if (!jpeg_converted){ if (!jpeg_converted){
@ -673,15 +678,13 @@ void handleMjpeg_task(void) {
if (jpeg_converted) { free(_jpg_buf); } if (jpeg_converted) { free(_jpg_buf); }
esp_camera_fb_return(wc_fb); esp_camera_fb_return(wc_fb);
//AddLog_P2(WC_LOGLEVEL, PSTR("CAM: send frame")); //AddLog_P2(WC_LOGLEVEL, PSTR("CAM: send frame"));
}
exit: if (0 == wc_stream_active) {
if (!wc_stream_active) {
AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Stream exit")); AddLog_P2(WC_LOGLEVEL, PSTR("CAM: Stream exit"));
client.flush(); client.flush();
client.stop(); client.stop();
} }
} }
}
void CamHandleRoot(void) { void CamHandleRoot(void) {
//CamServer->redirect("http://" + String(ip) + ":81/cam.mjpeg"); //CamServer->redirect("http://" + String(ip) + ":81/cam.mjpeg");
@ -750,13 +753,6 @@ void detect_motion(void) {
} }
} }
void wc_show_stream(void) {
if (CamServer) {
WSContentSend_P(PSTR("<p></p><center><img src='http://%s:81/stream' alt='Webcam stream' style='width:99%%;'></center><p></p>"),
WiFi.localIP().toString().c_str());
}
}
uint32_t wc_set_streamserver(uint32_t flag) { uint32_t wc_set_streamserver(uint32_t flag) {
if (global_state.wifi_down) { return 0; } if (global_state.wifi_down) { return 0; }
@ -783,17 +779,30 @@ uint32_t wc_set_streamserver(uint32_t flag) {
return 0; return 0;
} }
void WcStreamControl(uint32_t resolution) { void WcStreamControl() {
wc_set_streamserver(resolution); wc_set_streamserver(Settings.webcam_config.stream);
/*if (0 == resolution) { int resolution = (!Settings.webcam_config.stream) ? -1 : Settings.webcam_config.resolution;
resolution=-1;
}*/
wc_setup(resolution); wc_setup(resolution);
} }
void WcShowStream(void) {
if (Settings.webcam_config.stream) {
if (!CamServer) {
WcStreamControl();
delay(50); // Give the webcam webserver some time to prepare the stream
}
if (CamServer) {
WSContentSend_P(PSTR("<p></p><center><img src='http://%s:81/stream' alt='Webcam stream' style='width:99%%;'></center><p></p>"),
WiFi.localIP().toString().c_str());
}
}
}
void wc_loop(void) { void wc_loop(void) {
if (CamServer) { CamServer->handleClient(); } if (CamServer) {
CamServer->handleClient();
if (wc_stream_active) { handleMjpeg_task(); } if (wc_stream_active) { handleMjpeg_task(); }
}
if (motion_detect) { detect_motion(); } if (motion_detect) { detect_motion(); }
#ifdef USE_FACE_DETECT #ifdef USE_FACE_DETECT
if (face_detect_time) { detect_face(); } if (face_detect_time) { detect_face(); }
@ -833,34 +842,103 @@ red led = gpio 33
*/ */
void WcInit(void) { void WcInit(void) {
if (Settings.esp32_webcam_resolution > 10) { if (!Settings.webcam_config.data) {
Settings.esp32_webcam_resolution = 0; Settings.webcam_config.stream = 1;
Settings.webcam_config.resolution = 5;
Settings.webcam_config.flip = 0;
Settings.webcam_config.mirror = 0;
Settings.webcam_config.saturation = 0; // -2
Settings.webcam_config.brightness = 3; // 1
Settings.webcam_config.contrast = 2; // 0
} }
} }
/*********************************************************************************************\ /*********************************************************************************************\
* Commands * Commands
\*********************************************************************************************/ \*********************************************************************************************/
#define D_CMND_WEBCAM "Webcam" #define D_PRFX_WEBCAM "WC"
#define D_CMND_WC_STREAM "Stream"
#define D_CMND_WC_RESOLUTION "Resolution"
#define D_CMND_WC_MIRROR "Mirror"
#define D_CMND_WC_FLIP "Flip"
#define D_CMND_WC_SATURATION "Saturation"
#define D_CMND_WC_BRIGHTNESS "Brightness"
#define D_CMND_WC_CONTRAST "Contrast"
const char kWCCommands[] PROGMEM = "|" // no prefix const char kWCCommands[] PROGMEM = D_PRFX_WEBCAM "|" // Prefix
D_CMND_WEBCAM "|" D_CMND_WC_STREAM "|" D_CMND_WC_RESOLUTION "|" D_CMND_WC_MIRROR "|" D_CMND_WC_FLIP "|"
D_CMND_WC_SATURATION "|" D_CMND_WC_BRIGHTNESS "|" D_CMND_WC_CONTRAST
; ;
void (* const WCCommand[])(void) PROGMEM = { void (* const WCCommand[])(void) PROGMEM = {
&CmndWebcam, &CmndWebcam, &CmndWebcamStream, &CmndWebcamResolution, &CmndWebcamMirror, &CmndWebcamFlip,
&CmndWebcamSaturation, &CmndWebcamBrightness, &CmndWebcamContrast
}; };
void CmndWebcam(void) { void CmndWebcam(void) {
uint32_t flag = 0; Response_P(PSTR("{\"" D_PRFX_WEBCAM "\":{\"" D_CMND_WC_STREAM "\":%d,\"" D_CMND_WC_RESOLUTION "\":%d,\"" D_CMND_WC_MIRROR "\":%d,\""
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 10)) { D_CMND_WC_FLIP "\":%d,\""
Settings.esp32_webcam_resolution=XdrvMailbox.payload; D_CMND_WC_SATURATION "\":%d,\"" D_CMND_WC_BRIGHTNESS "\":%d,\"" D_CMND_WC_CONTRAST "\":%d}}"),
WcStreamControl(Settings.esp32_webcam_resolution); Settings.webcam_config.stream, Settings.webcam_config.resolution, Settings.webcam_config.mirror,
Settings.webcam_config.flip,
Settings.webcam_config.saturation -2, Settings.webcam_config.brightness -2, Settings.webcam_config.contrast -2);
} }
if (CamServer) { flag = 1; }
Response_P(PSTR("{\"" D_CMND_WEBCAM "\":{\"Streaming\":\"%s\"}"),GetStateText(flag)); void CmndWebcamStream(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
Settings.webcam_config.stream = XdrvMailbox.payload;
if (!Settings.webcam_config.stream) { WcStreamControl(); } // Stop stream
}
ResponseCmndStateText(Settings.webcam_config.stream);
}
void CmndWebcamResolution(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 10)) {
Settings.webcam_config.resolution = XdrvMailbox.payload;
wc_set_options(0, Settings.webcam_config.resolution);
}
ResponseCmndNumber(Settings.webcam_config.resolution);
}
void CmndWebcamMirror(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
Settings.webcam_config.mirror = XdrvMailbox.payload;
wc_set_options(3, Settings.webcam_config.mirror);
}
ResponseCmndStateText(Settings.webcam_config.mirror);
}
void CmndWebcamFlip(void) {
if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) {
Settings.webcam_config.flip = XdrvMailbox.payload;
wc_set_options(2, Settings.webcam_config.flip);
}
ResponseCmndStateText(Settings.webcam_config.flip);
}
void CmndWebcamSaturation(void) {
if ((XdrvMailbox.payload >= -2) && (XdrvMailbox.payload <= 2)) {
Settings.webcam_config.saturation = XdrvMailbox.payload +2;
wc_set_options(6, Settings.webcam_config.saturation -2);
}
ResponseCmndNumber(Settings.webcam_config.saturation -2);
}
void CmndWebcamBrightness(void) {
if ((XdrvMailbox.payload >= -2) && (XdrvMailbox.payload <= 2)) {
Settings.webcam_config.brightness = XdrvMailbox.payload +2;
wc_set_options(5, Settings.webcam_config.brightness -2);
}
ResponseCmndNumber(Settings.webcam_config.brightness -2);
}
void CmndWebcamContrast(void) {
if ((XdrvMailbox.payload >= -2) && (XdrvMailbox.payload <= 2)) {
Settings.webcam_config.contrast = XdrvMailbox.payload +2;
wc_set_options(4, Settings.webcam_config.contrast -2);
}
ResponseCmndNumber(Settings.webcam_config.contrast -2);
} }
/*********************************************************************************************\ /*********************************************************************************************\
@ -878,13 +956,7 @@ bool Xdrv81(uint8_t function) {
wc_pic_setup(); wc_pic_setup();
break; break;
case FUNC_WEB_ADD_MAIN_BUTTON: case FUNC_WEB_ADD_MAIN_BUTTON:
if (Settings.esp32_webcam_resolution) { WcShowStream();
//#ifndef USE_SCRIPT
WcStreamControl(Settings.esp32_webcam_resolution);
delay(50); // Give the webcam webserver some time to prepare the stream
wc_show_stream();
//#endif
}
break; break;
case FUNC_COMMAND: case FUNC_COMMAND:
result = DecodeCommand(kWCCommands, WCCommand); result = DecodeCommand(kWCCommands, WCCommand);