* The URL handler for streaming repeatedly sends the image data captured by * the sensor as a series of JPEG frames (Motion-JPEG) of multipart content. * @param req The httpd_req_t structure passed from httpd. * @return ESP_OK Image data has sent * @return ESP_FAIL */
| 390 | * @return ESP_FAIL |
| 391 | */ |
| 392 | esp_err_t ESP32WebCam::_streamHandler(httpd_req_t* req) { |
| 393 | static const char bcharsnospace[] = "'()+,-./0123456789:=?abcdefghijklmnopqrstuvwxyz_ABCDEFGHIJKLMNOPQRSTUVWXYZ"; |
| 394 | char boundary[33]; |
| 395 | char mime[sizeof(_CONTENT_TYPE) + sizeof(boundary)]; |
| 396 | char contentBoundary[sizeof(boundary) + 6]; |
| 397 | |
| 398 | // Assemble a boundary string from pseudo-random numbers. |
| 399 | srand(esp_timer_get_time()); |
| 400 | uint8_t c = 0; |
| 401 | while (c < sizeof(boundary) - 1) |
| 402 | boundary[c++] = bcharsnospace[(int)_random(sizeof(bcharsnospace) - 1)]; |
| 403 | boundary[c] = '\0'; |
| 404 | sprintf(mime, _CONTENT_TYPE, (const char*)boundary); |
| 405 | sprintf(contentBoundary, _CONTENT_BOUNDARY, (const char*)boundary); |
| 406 | |
| 407 | // Send headers |
| 408 | // HTTP/1.1 200 |
| 409 | // Content-Type: multipart/x-mixed-replace;boundary={contentBoundary} |
| 410 | // Access-Control-Allow-Origin: * |
| 411 | // X-Framerate: 60 |
| 412 | httpd_resp_set_type(req, mime); |
| 413 | httpd_resp_set_hdr(req, ESP32WebCam::_ACCESS_CONTROL_ALLOW_ORIGIN, "*"); |
| 414 | httpd_resp_set_hdr(req, "X-Framerate", "60"); |
| 415 | |
| 416 | // Repeated transmission of captured JPEG frames |
| 417 | esp_err_t rc = ESP_OK; |
| 418 | while (rc == ESP_OK) { |
| 419 | uint8_t* jpegBuffer; |
| 420 | size_t jpegSize; |
| 421 | |
| 422 | // Indicates the output buffer of the image sensor. |
| 423 | camera_fb_t* fb = esp_camera_fb_get(); |
| 424 | |
| 425 | if (fb) { |
| 426 | if (fb->format == PIXFORMAT_JPEG) { |
| 427 | // If the pixel format of the image sensor is JPEG, it can be read |
| 428 | // directly from the frame buffer. |
| 429 | jpegBuffer = fb->buf; |
| 430 | jpegSize = fb->len; |
| 431 | } |
| 432 | else { |
| 433 | // If the scene is not in JPEG format, it will attempt to revert to |
| 434 | // JPEG, but this does not always work. Since most of the failures are |
| 435 | // due to lack of memory, you can avoid conversion errors by reducing |
| 436 | // the JPEG quality of the resulting image. |
| 437 | bool jpegcc = frame2jpg(fb, 80, &jpegBuffer, &jpegSize); |
| 438 | esp_camera_fb_return(fb); |
| 439 | fb = nullptr; |
| 440 | if (!jpegcc) { |
| 441 | _sendResponse(req, 500, "text/plain", "_streamHandler failed to frame2jpg"); |
| 442 | rc = ESP_FAIL; |
| 443 | break; |
| 444 | } |
| 445 | } |
| 446 | } |
| 447 | else { |
| 448 | _sendResponse(req, 500, "text/plain", "_streamHandler failed to esp_camera_fb_get"); |
| 449 | rc = ESP_FAIL; |
nothing calls this directly
no outgoing calls
no test coverage detected