In diesem Tutorial lernst du, wie du Video von einem ESP32-CAM über dein lokales Wi‑Fi-Netzwerk in deinen Webbrowser streamst. So kannst du zum Beispiel eine kabellose Überwachungskamera bauen, die du vom Computer aus beobachten kannst.
Benötigte Teile
Du benötigst ein ESP32-CAM, um die Codebeispiele auszuprobieren. Du kannst ein ESP32-CAM mit einem USB-TTL Shield zum Programmieren oder einen FTDI USB-TTL Adapter bekommen. Der FTDI USB-TTL Adapter ist etwas umständlicher in der Handhabung, lässt dafür aber die GPIO-Pins frei zugänglich. Für dieses Tutorial empfehle ich das USB-TTL Shield, achte aber darauf, das richtige zu kaufen (siehe die Programming the ESP32-CAM Anleitung für Details).

ESP32-CAM mit USB-TTL Shield

FTDI USB-TTL Adapter
Makerguides is a participant in affiliate advertising programs designed to provide a means for sites to earn advertising fees by linking to Amazon, AliExpress, Elecrow, and other sites. As an Affiliate we may earn from qualifying purchases.
Video-Streaming
In diesem Projekt implementieren wir einen Video-Streaming-Server, der auf dem ESP32-CAM läuft. Das ESP32-CAM macht Bilder und stellt sie über Wi‑Fi bereit. Der Wi‑Fi-Router transportiert diese Bilder zum Webbrowser, der sie als Videostream anzeigt. Die Abbildung unten zeigt den Aufbau:

Beachte, dass der Videostream nicht verschlüsselt oder gesichert ist, sondern nur unter einer URL in deinem lokalen Wi‑Fi-Netz sichtbar ist, z. B. 192.168.2.39/stream. Nur jemand mit Zugriff auf dein Wi‑Fi-Netzwerk kann den Videostream sehen.
Code für den Video-Server
Das folgende Arduino-Sketch richtet den Videostream-Server ein, der einen kontinuierlichen MJPEG-Stream vom ESP32-CAM an jeden Webbrowser sendet, der mit demselben Wi‑Fi-Netz verbunden ist.
Für diesen Code verwenden wir die esp32cam library, die die Handhabung der Kamera vereinfacht. Du kannst sie über den Library Manager in der Arduino IDE installieren. Suche einfach nach „esp32cam“ und drücke INSTALL. Die Abbildung unten zeigt die abgeschlossene Installation:

Unten findest du den vollständigen Code für den Videostream-Server. Schau ihn dir kurz an, dann besprechen wir die Details:
#include "WebServer.h"
#include "WiFi.h"
#include "esp32cam.h"
const char* WIFI_SSID = "SSID";
const char* WIFI_PASS = "PASSWORD";
const char* URL = "/stream";
const int FRAMERATE = 10;
const auto RESOLUTION = esp32cam::Resolution::find(1024, 768);
WebServer server(80);
void handleStream() {
static char head[128];
WiFiClient client = server.client();
server.sendContent("HTTP/1.1 200 OK\r\n"
"Content-Type: multipart/x-mixed-replace; "
"boundary=frame\r\n\r\n");
while (client.connected()) {
auto frame = esp32cam::capture();
if (frame) {
sprintf(head,
"--frame\r\n"
"Content-Type: image/jpeg\r\n"
"Content-Length: %ul\r\n\r\n",
frame->size());
client.write(head, strlen(head));
frame->writeTo(client);
client.write("\r\n");
}
delay(1000 / FRAMERATE);
}
}
void initCamera() {
using namespace esp32cam;
Config cfg;
cfg.setPins(pins::AiThinker);
cfg.setResolution(RESOLUTION);
cfg.setBufferCount(2);
cfg.setJpeg(80);
Camera.begin(cfg);
}
void initWifi() {
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
}
Serial.printf("Stream at: http://%s%s\n",
WiFi.localIP().toString().c_str(), URL);
}
void initServer() {
server.on(URL, handleStream);
server.begin();
}
void setup() {
Serial.begin(115200);
initWifi();
initCamera();
initServer();
}
void loop() {
server.handleClient();
}
Bibliotheken
Das Sketch beginnt mit dem Einbinden der notwendigen Bibliotheken:
#include "WebServer.h" #include "WiFi.h" #include "esp32cam.h"
Diese Bibliotheken ermöglichen HTTP-Server-Funktionalität (WebServer.h), Wi‑Fi-Konnektivität (WiFi.h), und Kamerasteuerung mit dem ESP32-CAM (esp32cam.h).
Konstanten
Als Nächstes werden einige Konstanten definiert:
const char* WIFI_SSID = "SSID"; const char* WIFI_PASS = "PASSWORD"; const char* URL = "/stream"; const int FRAMERATE = 10; const auto RESOLUTION = esp32cam::Resolution::find(1024, 768);
Die WIFI_SSID und WIFI_PASS Variablen speichern die Zugangsdaten für das Wi‑Fi-Netzwerk. Du musst SSID und PASSWORD durch die tatsächlichen Anmeldedaten deines Wi‑Fi-Netzes ersetzen.
Der URL ist der Pfad, unter dem der Videostream bereitgestellt wird. Du kannst das nach Belieben ändern. Zum Beispiel „/video“ oder „/frontdoor“, achte nur darauf, den Schrägstrich (‚/‘) am Anfang beizubehalten.
Die FRAMERATE Variable legt fest, wie viele Bilder pro Sekunde an den Client gesendet werden. Und die RESOLUTION setzt die gewünschte Auflösung für die Kamera mit der esp32cam Bibliothek.
Hier ist eine Liste möglicher Kameraauflösungen; je nach Kamera funktionieren möglicherweise nicht alle davon:
- 96×96
- 160×120
- 128×128
- 176×144
- 240×176
- 240×240
- 320×240
- 320×320
- 400×296
- 480×320
- 640×480
- 800×600
- 1024×768
- 1280×720
- 1280×1024
- 1600×1200
Du kannst die Liste der Kameraauflösungen mit der folgenden Funktion ausgeben:
void printResolutions() {
Serial.println("Camera resolutions:");
for (auto res : esp32cam::Camera.listResolutions()) {
Serial.printf("%dx%d\n", res.getWidth(), res.getHeight());
}
}
Beachte, dass die Auflösung die maximale Bildrate beeinflusst. Bei einer Auflösung von 1600×1200 wirst du nicht viel mehr als 10 Bilder pro Sekunde erreichen.
Objekte
Die folgende Zeile erzeugt ein HTTP-Server-Objekt, das auf Port 80 lauscht. Das ist unser Webserver, der den Videostream bereitstellt.
WebServer server(80);
handleStream
Die Funktion handleStream() verarbeitet den Videostream, sobald ein Client auf den /stream Pfad zugreift:
void handleStream() {
static char head[128];
WiFiClient client = server.client();
Diese Zeile ermittelt den aktuell mit dem Server verbundenen Client. Danach wird die Antwort vorbereitet:
server.sendContent("HTTP/1.1 200 OK\r\n"
"Content-Type: multipart/x-mixed-replace; "
"boundary=frame\r\n\r\n");
Dieser Header teilt dem Browser mit, dass er einen multipart-MJPEG-Stream erhält, bei dem jeder Teil durch eine Grenze namens frame getrennt ist.
Innerhalb einer Schleife erfasst die Funktion ein Frame von der Kamera:
while (client.connected()) {
auto frame = esp32cam::capture();
Wird ein Frame erfolgreich erfasst, wird ein Header erstellt, der das JPEG-Bild beschreibt:
if (frame) {
sprintf(head,
"--frame\r\n"
"Content-Type: image/jpeg\r\n"
"Content-Length: %ul\r\n\r\n",
frame->size());
client.write(head, strlen(head));
frame->writeTo(client);
client.write("\r\n");
}
Das Bild wird als JPEG an den Client gesendet, und die Schleife wartet kurz entsprechend der Bildrate:
delay(1000 / FRAMERATE);
Beachte, dass diese FRAMERATE-Konstante es nur erlaubt, die Bildrate unterhalb der maximal vom ESP32-CAM für die gewählte Auflösung möglichen Bildrate zu verlangsamen. Wenn du immer mit der maximalen Bildrate arbeiten möchtest, entferne einfach diese Zeile.
initCamera
Die initCamera() Funktion konfiguriert und startet die ESP32-CAM-Hardware:
void initCamera() {
using namespace esp32cam;
Config cfg;
cfg.setPins(pins::AiThinker);
cfg.setResolution(RESOLUTION);
cfg.setBufferCount(2);
cfg.setJpeg(80);
Camera.begin(cfg);
}
Hier wird ein Config-Objekt erstellt. Die setPins-Funktion konfiguriert die Kamerapins basierend auf dem AiThinker-Board-Layout. setResolution legt die zu verwendende Auflösung fest, während setBufferCount bestimmt, wie viele Bildpuffer intern verwendet werden.
Die setJpeg-Funktion setzt die JPEG-Kompressionsqualität. 80 ist ein guter Kompromiss zwischen Qualität und Dateigröße. 90 liefert bessere Qualität, aber eine geringere Reduktion der Dateigröße. Für schnelleres Video kannst du die Auflösung und die JPEG-Kompression reduzieren, allerdings erhältst du dann kleinere Bilder mit geringerer Qualität.
Schließlich initialisiert Camera.begin(cfg) die Kamera mit diesen Einstellungen.
initWifi
Die initWifi() Funktion verbindet das ESP32-CAM mit dem angegebenen Wi‑Fi-Netzwerk:
void initWifi() {
WiFi.persistent(false);
WiFi.mode(WIFI_STA);
WiFi.begin(WIFI_SSID, WIFI_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(100);
}
Serial.printf("Stream at: http://%s%s\n",
WiFi.localIP().toString().c_str(), URL);
}
WiFi.persistent(false) deaktiviert das Schreiben der Zugangsdaten in den Flash, was die Wiederverbindung beschleunigt. Das Gerät wird in den station mode (WIFI_STA), gesetzt und versucht, mit den angegebenen Zugangsdaten eine Verbindung zum Wi‑Fi herzustellen.
Sobald die Verbindung steht, werden die IP-Adresse und der Stream-Pfad im Serial Monitor ausgegeben. Du musst diese URL aus dem Serial Monitor in die Adresszeile deines Browsers kopieren, um den Videostream zu sehen. Die tatsächliche URL hängt von deinem ESP32-CAM ab, und du kannst das Suffix „stream“ ändern. Bei mir erscheint im Serial Monitor z. B.:

Ich kopiere daher „http://192.168.2.39/stream“ in die Adressleiste meines Chrome-Browsers, um auf das Video zuzugreifen.
initServer
Die initServer() Funktion verknüpft den Streaming-Pfad mit dem Handler und startet den Server:
void initServer() {
server.on(URL, handleStream);
server.begin();
}
Das mappt jede Anfrage an /stream auf die handleStream() Funktion und startet dann den Server.
setup
Die setup() Funktion läuft einmal beim Booten:
void setup() {
Serial.begin(115200);
initWifi();
initCamera();
initServer();
}
Sie startet die serielle Kommunikation, verbindet sich mit dem Wi‑Fi, initialisiert die Kamera und richtet den Webserver ein.
loop
Schließlich ruft die loop() Funktion kontinuierlich eingehende HTTP-Anfragen ab und bearbeitet sie:
void loop() {
server.handleClient();
}
Diese Zeile erlaubt dem ESP32-CAM, auf Client-Anfragen zu reagieren, indem registrierte Handler wie handleStream() aufgerufen werden.
Insgesamt erstellt dieser Code einen einfachen, aber effektiven MJPEG-Streaming-Server, der von jedem Webbrowser im selben Netzwerk aufgerufen werden kann und einen Live-Kamerafeed vom ESP32-CAM liefert.
Zum Herunterladen dieses Codes auf dein ESP32-CAM-Modul wähle das AI Thinker ESP32-CAM Board und versetze dann das ESP32-CAM in den Download-Modus.

Wenn du dabei Hilfe brauchst, schau dir das Programming the ESP32-CAM Tutorial an.
Fazit
In diesem Tutorial hast du gelernt, wie du Video von einem ESP32-CAM über dein lokales Wi‑Fi-Netzwerk in deinen Webbrowser streamst.
Wenn du Objekte im Videostream erkennen möchtest, sieh dir unser Object Detection with ESP32-CAM and YOLO Tutorial an. Wenn du ein bewegungsaktiviertes Überwachungssystem bauen willst, könnte das Motion Activated ESP32-CAM Tutorial hilfreich sein.
Sieh dir auch das More GPIO pins for ESP32-CAM Tutorial an, wenn du mehr GPIO-Pins zur Steuerung deines Überwachungssystems brauchst. Alternativ könntest du auch ein anderes Board mit mehr GPIOs in Betracht ziehen, wie das XIAO-ESP32-S3-Sense oder das ESP32-WROVER CAM.
Schließlich möchtest du vielleicht die Blitz-LED des ESP32-CAM einschalten, wenn du die Kamera in einer dunklen Umgebung betreibst. Sieh dir das Control ESP32-CAM Flash LED Tutorial für weitere Details an.
Wenn du Fragen hast, hinterlasse sie gerne im Kommentarbereich.
Viel Tüftelspaß ; )

