added code
This commit is contained in:
@@ -0,0 +1,178 @@
|
|||||||
|
/*
|
||||||
|
Waveshare ESP32-S3-ETH + OV5640 RTSP/MJPEG camera
|
||||||
|
|
||||||
|
Install first in Arduino IDE Library Manager:
|
||||||
|
ESP32-RTSPServer by Richard Sachse (version 1.3.5 or newer)
|
||||||
|
|
||||||
|
Open in VLC: rtsp://<Ethernet-IP>:8554/
|
||||||
|
|
||||||
|
This is MJPEG carried over RTSP, not H.264. The stream is 720p (1280x720).
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <SPI.h>
|
||||||
|
#include <ETH.h>
|
||||||
|
#include <ESPmDNS.h>
|
||||||
|
#include <NetworkUdp.h>
|
||||||
|
#include <ArduinoOTA.h>
|
||||||
|
#include "esp_camera.h"
|
||||||
|
#include <ESP32-RTSPServer.h>
|
||||||
|
|
||||||
|
constexpr int ETH_MOSI = 11, ETH_MISO = 12, ETH_SCK = 13;
|
||||||
|
constexpr int ETH_CS = 14, ETH_RST = 9, ETH_INT = 10, ETH_ADDR = 1;
|
||||||
|
constexpr int CAMERA_POWER = 8; // Active-low power enable on ESP32-S3-ETH.
|
||||||
|
const char *otaHostname = "esp32s3-camera-node";
|
||||||
|
const char *otaPassword = "1gYh0Y";
|
||||||
|
uint32_t last_ota_time = 0;
|
||||||
|
|
||||||
|
SPIClass ethSpi(FSPI);
|
||||||
|
static bool ethConnected = false;
|
||||||
|
|
||||||
|
RTSPServer rtspServer;
|
||||||
|
TaskHandle_t videoTaskHandle = nullptr;
|
||||||
|
int cameraQuality = 20;
|
||||||
|
|
||||||
|
static bool startCamera() {
|
||||||
|
camera_config_t config = {};
|
||||||
|
config.ledc_channel = LEDC_CHANNEL_0;
|
||||||
|
config.ledc_timer = LEDC_TIMER_0;
|
||||||
|
config.pin_d0 = 41; config.pin_d1 = 45; config.pin_d2 = 46; config.pin_d3 = 42;
|
||||||
|
config.pin_d4 = 40; config.pin_d5 = 38; config.pin_d6 = 15; config.pin_d7 = 18;
|
||||||
|
config.pin_xclk = 3; config.pin_pclk = 39; config.pin_vsync = 1; config.pin_href = 2;
|
||||||
|
config.pin_sccb_sda = 48; config.pin_sccb_scl = 47;
|
||||||
|
config.pin_pwdn = -1; config.pin_reset = -1;
|
||||||
|
config.xclk_freq_hz = 10000000;
|
||||||
|
config.pixel_format = PIXFORMAT_JPEG;
|
||||||
|
config.frame_size = FRAMESIZE_HD; // 1280x720 (720p). Requires PSRAM.
|
||||||
|
config.jpeg_quality = cameraQuality; // Higher number = smaller/lower-quality JPEG.
|
||||||
|
config.fb_count = 1;
|
||||||
|
config.fb_location = psramFound() ? CAMERA_FB_IN_PSRAM : CAMERA_FB_IN_DRAM;
|
||||||
|
config.grab_mode = CAMERA_GRAB_WHEN_EMPTY;
|
||||||
|
|
||||||
|
esp_err_t error = esp_camera_init(&config);
|
||||||
|
if (error != ESP_OK) {
|
||||||
|
Serial.printf("Camera init failed: 0x%x\n", error);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sendVideo(void *) {
|
||||||
|
while (true) {
|
||||||
|
if (rtspServer.readyToSendFrame()) {
|
||||||
|
camera_fb_t *frame = esp_camera_fb_get();
|
||||||
|
if (frame) {
|
||||||
|
rtspServer.sendRTSPFrame(frame->buf, frame->len, cameraQuality, frame->width, frame->height);
|
||||||
|
esp_camera_fb_return(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vTaskDelay(pdMS_TO_TICKS(1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void startOTA() {
|
||||||
|
// Explicit mDNS binding before ArduinoOTA prevents unreliable Ethernet OTA discovery.
|
||||||
|
if (!MDNS.begin(otaHostname)) {
|
||||||
|
Serial.println("mDNS responder setup failed!");
|
||||||
|
}
|
||||||
|
ArduinoOTA.setHostname(otaHostname);
|
||||||
|
ArduinoOTA.setPassword(otaPassword);
|
||||||
|
ArduinoOTA
|
||||||
|
.onStart([]() {
|
||||||
|
String type = ArduinoOTA.getCommand() == U_FLASH ? "sketch" : "filesystem";
|
||||||
|
Serial.println("Start updating " + type);
|
||||||
|
})
|
||||||
|
.onEnd([]() {
|
||||||
|
Serial.println("\nEnd");
|
||||||
|
})
|
||||||
|
.onProgress([](unsigned int progress, unsigned int total) {
|
||||||
|
if (millis() - last_ota_time > 500) {
|
||||||
|
Serial.printf("Progress: %u%%\n", progress / (total / 100));
|
||||||
|
last_ota_time = millis();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.onError([](ota_error_t error) {
|
||||||
|
Serial.printf("Error[%u]: ", error);
|
||||||
|
if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed");
|
||||||
|
else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed");
|
||||||
|
else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed");
|
||||||
|
else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed");
|
||||||
|
else if (error == OTA_END_ERROR) Serial.println("End Failed");
|
||||||
|
});
|
||||||
|
ArduinoOTA.begin();
|
||||||
|
Serial.println("Ready");
|
||||||
|
Serial.print("IP address: ");
|
||||||
|
Serial.println(ETH.localIP());
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onEthEvent(arduino_event_id_t event, arduino_event_info_t info) {
|
||||||
|
switch (event) {
|
||||||
|
case ARDUINO_EVENT_ETH_START:
|
||||||
|
Serial.println("ETH: Started, setting hostname.");
|
||||||
|
ETH.setHostname(otaHostname);
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_CONNECTED:
|
||||||
|
Serial.println("ETH: Link up.");
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_GOT_IP:
|
||||||
|
Serial.print("ETH: Got IP: ");
|
||||||
|
Serial.println(ETH.localIP());
|
||||||
|
ethConnected = true;
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_DISCONNECTED:
|
||||||
|
Serial.println("ETH: Link down.");
|
||||||
|
ethConnected = false;
|
||||||
|
break;
|
||||||
|
case ARDUINO_EVENT_ETH_STOP:
|
||||||
|
Serial.println("ETH: Stopped.");
|
||||||
|
ethConnected = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
delay(1000);
|
||||||
|
Serial.println("\nESP32-S3 Ethernet RTSP camera starting");
|
||||||
|
|
||||||
|
// Required for camera power on this Waveshare board.
|
||||||
|
pinMode(CAMERA_POWER, OUTPUT);
|
||||||
|
digitalWrite(CAMERA_POWER, LOW);
|
||||||
|
delay(200);
|
||||||
|
|
||||||
|
Network.onEvent(onEthEvent);
|
||||||
|
ethSpi.begin(ETH_SCK, ETH_MISO, ETH_MOSI);
|
||||||
|
Serial.println("Network: Initializing W5500 over SPI...");
|
||||||
|
if (!ETH.begin(ETH_PHY_W5500, ETH_ADDR, ETH_CS, ETH_INT, ETH_RST, ethSpi)) {
|
||||||
|
Serial.println("Network: Fatal error - W5500 initialization failed.");
|
||||||
|
while (true) delay(1000);
|
||||||
|
}
|
||||||
|
Serial.println("Network: Waiting for DHCP lease...");
|
||||||
|
unsigned long dhcpWaitStart = millis();
|
||||||
|
while (!ethConnected && millis() - dhcpWaitStart < 15000) {
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
if (!ethConnected) {
|
||||||
|
Serial.println("Connection Failed! Rebooting...");
|
||||||
|
delay(5000);
|
||||||
|
ESP.restart();
|
||||||
|
}
|
||||||
|
startOTA();
|
||||||
|
if (!startCamera()) return;
|
||||||
|
|
||||||
|
rtspServer.transport = RTSPServer::VIDEO_ONLY;
|
||||||
|
rtspServer.rtspPort = 8554;
|
||||||
|
if (!rtspServer.init(RTSPServer::VIDEO_ONLY, 8554)) {
|
||||||
|
Serial.println("RTSP server failed to start");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
xTaskCreate(sendVideo, "RTSP video", 5 * 1024, nullptr, 5, &videoTaskHandle);
|
||||||
|
Serial.printf("RTSP ready: rtsp://%s:8554/\n", ETH.localIP().toString().c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
ArduinoOTA.handle();
|
||||||
|
delay(2);
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user