From 19b8f77d57bc6b75e5d9999658da6b50456d28e1 Mon Sep 17 00:00:00 2001 From: Rene Zeldenthuis Date: Sat, 25 Mar 2023 21:39:11 +0100 Subject: [PATCH] Added JPEG Motion streaming --- README.md | 19 +++++++++++++++++-- html/index.html | 11 +++++++---- include/html_data.h | 2 +- src/main.cpp | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 58 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 1b96083..705766b 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,29 @@ [![Platform IO CI](https://github.com/rzeldent/esp32cam-rtsp/actions/workflows/main.yml/badge.svg)](https://github.com/rzeldent/esp32cam-rtsp/actions/workflows/main.yml) -Simple [RTSP](https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol) server. +Simple [RTSP](https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol), [HTTP JPEG Streamer](https://en.wikipedia.org/wiki/Motion_JPEG) and server. Easy configuration through the web interface. -Flashing this software on a ESP32CAM module will make it a **RTSP streaming camera** server. +Flashing this software on a ESP32CAM module will make it a **RTSP streaming camera** server, a **HTTP Motion JPEG streamer*** and a **HTTP image server**. + +### RTSP The RTSP protocol is an industry standard and allows many CCTV systems and applications (like for example [VLC](https://www.videolan.org/vlc/)) to connect directly to the ESP32CAM camera stream. It is also possible to stream directly to a server using [ffmpeg](https://ffmpeg.org). This makes the module a camera server allowing recording and the stream can be stored on a disk and replayed later. +The URL is rtsp://<ip address of the module>:554/mjpeg/1 + +### HTTP Motion JPEG +The HTTP JPEG streamer makes it possible to watch the camera stream directly in your browser. + +The URL is http://<ip address of the module>/stream + +### HTTP image server +The HTTP Image server returns an HTTP jpeg image of the camera. + +The URL is http://<ip address of the module>/snapshot + + This software supports the following ESP32-CAM (and alike) modules: - ESP32CAM diff --git a/html/index.html b/html/index.html index 7bf10b3..7276492 100644 --- a/html/index.html +++ b/html/index.html @@ -273,14 +273,17 @@
- The camera RTSP stream can be found at: - rtsp://{{IpV4}}:{{RtspPort}}/mjpeg/1 + RTSP camera stream: rtsp://{{IpV4}}:{{RtspPort}}/mjpeg/1
- A snapshot of the camera can be found at: - http://{{IpV4}}/snapshot + JPEG Motion stream: http://{{IpV4}}/stream + +
+
+ + Snapshot of the camera: http://{{IpV4}}/snapshot
diff --git a/include/html_data.h b/include/html_data.h index a60e817..792a21d 100644 --- a/include/html_data.h +++ b/include/html_data.h @@ -4,5 +4,5 @@ // ****************************************************************************** -constexpr char file_data_index_html[] = "{{AppTitle}} v{{AppVersion}}

{{ThingName}}


{{#ConfigChanged}} {{/ConfigChanged}}
ESP32
CPU model:
{{ChipModel}} rev. {{ChipRevision}}
CPU speed:
{{CpuFreqMHz}} Mhz
CPU cores:
{{CpuCores}}
RAM size:
{{HeapSize}}
PSRAM size:
{{PsRamSize}}
Flash size:
{{FlashSize}}
Diagnostics
Uptime:
{{Uptime}}
RTSP sessions:
{{NumRTSPSessions}}
Free heap:
{{FreeHeap}}
Max free block:
{{MaxAllocHeap}}
Peripheral
Board type:
{{BoardType}}
LED intensity:
{{LedIntensity}} [0-100]
Network
Host name:
{{HostName}}
Mac address:
{{MacAddress}}
Wifi mode:
{{WifiMode}}
Access point:
{{AccessPoint}}
Signal strength:
{{SignalStrength}} dbm
IPv4 address:
{{IpV4}}
IPv6 address:
{{IpV6}}
{{#NetworkState.ApMode}} {{/NetworkState.ApMode}} {{#NetworkState.OnLine}} {{/NetworkState.OnLine}}
Camera
Frame rate:
{{FrameDuration}} ms ({{FrameFrequency}} f/s)
Frame size:
{{FrameSize}}
Frame buffer location:
{{FrameBufferLocation}}
Frame buffers:
{{FrameBuffers}}
JPEG quality:
{{JpegQuality}} [1-100]
Brightness:
{{Brightness}} [-2,2]
Contrast:
{{Contrast}} [-2,2]
Saturation:
{{Saturation}} [-2,2]
Special effect:
{{SpecialEffect}}
White balance:
{{WhiteBal}}
AWB gain:
{{AwbGain}}
WB mode:
{{WbMode}}
Exposure control:
{{ExposureCtrl}}
Auto exposure control (dsp):
{{Aec2}}
Auto Exposure level:
{{AeLevel}}
Manual exposure value:
{{AecValue}}
Gain control:
{{GainCtrl}}
AGC gain:
{{AgcGain}}
Gain ceiling:
{{GainCeiling}}
Black pixel correct:
{{Bpc}}
White pixel correct:
{{Wpc}}
Gamma correct:
{{RawGma}}
Lens correction:
{{Lenc}}
Horizontal mirror:
{{HMirror}}
Vertical flip:
{{VFlip}}
Downsize enable:
{{Dcw}}
Color bar:
{{ColorBar}}
{{#CameraInitialized}} {{/CameraInitialized}} {{^CameraInitialized}} {{/CameraInitialized}}
Special URLs / API
The camera RTSP stream can be found at: rtsp://{{IpV4}}:{{RtspPort}}/mjpeg/1
A snapshot of the camera can be found at: http://{{IpV4}}/snapshot
The intensity of the flash led (0-255) can be controlled using: http://{{IpV4}}/flash?v=value. Authentication is required and if no value is present, the configuration value is used.
Restarting the camera can be done using: http://{{IpV4}}/restart. Authentication is required.
"; +constexpr char file_data_index_html[] = "{{AppTitle}} v{{AppVersion}}

{{ThingName}}


{{#ConfigChanged}} {{/ConfigChanged}}
ESP32
CPU model:
{{ChipModel}} rev. {{ChipRevision}}
CPU speed:
{{CpuFreqMHz}} Mhz
CPU cores:
{{CpuCores}}
RAM size:
{{HeapSize}}
PSRAM size:
{{PsRamSize}}
Flash size:
{{FlashSize}}
Diagnostics
Uptime:
{{Uptime}}
RTSP sessions:
{{NumRTSPSessions}}
Free heap:
{{FreeHeap}}
Max free block:
{{MaxAllocHeap}}
Peripheral
Board type:
{{BoardType}}
LED intensity:
{{LedIntensity}} [0-100]
Network
Host name:
{{HostName}}
Mac address:
{{MacAddress}}
Wifi mode:
{{WifiMode}}
Access point:
{{AccessPoint}}
Signal strength:
{{SignalStrength}} dbm
IPv4 address:
{{IpV4}}
IPv6 address:
{{IpV6}}
{{#NetworkState.ApMode}} {{/NetworkState.ApMode}} {{#NetworkState.OnLine}} {{/NetworkState.OnLine}}
Camera
Frame rate:
{{FrameDuration}} ms ({{FrameFrequency}} f/s)
Frame size:
{{FrameSize}}
Frame buffer location:
{{FrameBufferLocation}}
Frame buffers:
{{FrameBuffers}}
JPEG quality:
{{JpegQuality}} [1-100]
Brightness:
{{Brightness}} [-2,2]
Contrast:
{{Contrast}} [-2,2]
Saturation:
{{Saturation}} [-2,2]
Special effect:
{{SpecialEffect}}
White balance:
{{WhiteBal}}
AWB gain:
{{AwbGain}}
WB mode:
{{WbMode}}
Exposure control:
{{ExposureCtrl}}
Auto exposure control (dsp):
{{Aec2}}
Auto Exposure level:
{{AeLevel}}
Manual exposure value:
{{AecValue}}
Gain control:
{{GainCtrl}}
AGC gain:
{{AgcGain}}
Gain ceiling:
{{GainCeiling}}
Black pixel correct:
{{Bpc}}
White pixel correct:
{{Wpc}}
Gamma correct:
{{RawGma}}
Lens correction:
{{Lenc}}
Horizontal mirror:
{{HMirror}}
Vertical flip:
{{VFlip}}
Downsize enable:
{{Dcw}}
Color bar:
{{ColorBar}}
{{#CameraInitialized}} {{/CameraInitialized}} {{^CameraInitialized}} {{/CameraInitialized}}
Special URLs / API
JPEG Motion stream: http://{{IpV4}}/stream
Snapshot of the camera: http://{{IpV4}}/snapshot
The intensity of the flash led (0-255) can be controlled using: http://{{IpV4}}/flash?v=value. Authentication is required and if no value is present, the configuration value is used.
Restarting the camera can be done using: http://{{IpV4}}/restart. Authentication is required.
"; constexpr char file_data_restart_html[] = "{{AppTitle}} v{{AppVersion}}

{{ThingName}}


Restart

The device is restarting.


In some cases, the device requires a hard reset (power cycle).

If this page takes longer than a minute, consider performing a power cycle.

Restarting...
"; diff --git a/src/main.cpp b/src/main.cpp index cb3f09a..08074ae 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -213,6 +213,36 @@ void handle_snapshot() web_server.sendContent(fb, fb_len); } +#define STREAM_CONTENT_BOUNDARY "123456789000000000000987654321" + +void handle_stream() +{ + log_v("handle_stream"); + if (camera_init_result != ESP_OK) + { + web_server.send(404, "text/plain", "Camera is not initialized"); + return; + } + + log_v("starting streaming"); + char size_buf[12]; + auto client = web_server.client(); + client.write("HTTP/1.1 200 OK\r\nAccess-Control-Allow-Origin: *\r\nContent-Type: multipart/x-mixed-replace; boundary=" STREAM_CONTENT_BOUNDARY "\r\n"); + while (client.connected()) + { + client.write("\r\n--" STREAM_CONTENT_BOUNDARY "\r\n"); + cam.run(); + client.write("Content-Type: image/jpeg\r\nContent-Length: "); + sprintf(size_buf, "%d\r\n\r\n", cam.getSize()); + client.write(size_buf); + client.write(cam.getfb(), cam.getSize()); + } + + log_v("client disconnected"); + client.stop(); + log_v("stopped streaming"); +} + void handle_flash() { log_v("handle_flash"); @@ -402,6 +432,9 @@ void setup() web_server.on("/restart", HTTP_GET, handle_restart); // Camera snapshot web_server.on("/snapshot", HTTP_GET, handle_snapshot); + // Camera stream + web_server.on("/stream", HTTP_GET, handle_stream); + // Camera flash light web_server.on("/flash", HTTP_GET, handle_flash);