Skip to Content

Transmitir vídeo con XIAO-ESP32-S3-Sense

Transmitir vídeo con XIAO-ESP32-S3-Sense

En este tutorial aprenderás cómo transmitir vídeo desde un Seeed Studio XIAO-ESP32-S3 Sense a través de tu red Wi-Fi local a tu navegador web. Esto te permite construir tu propio sistema de cámara de vigilancia inalámbrica que puedes monitorear desde tu ordenador.

Si no has usado antes el XIAO-ESP32-S3 Sense, echa un vistazo al Getting started with XIAO-ESP32-S3-Sense tutorial primero, que te ayudará a empezar con la placa.

Partes necesarias

Obviamente, necesitarás una placa XIAO-ESP32-S3 Sense de Seeed Studio para probar los ejemplos de código. Ten en cuenta que la placa puede calentarse mucho, por ejemplo, al transmitir vídeo con una alta tasa de frames. Te recomiendo que coloques un pequeño Heatsink en la parte trasera de la placa (ver la pieza listada abajo).

Seeed Studio XIAO ESP32 S3 Sense

Cable USB C

Pequeño disipador de calor 9×9 mm

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.

Transmisión de vídeo

En este proyecto vamos a implementar un servidor de transmisión de vídeo que se ejecuta en el XIAO-ESP32-S3 Sense. La cámara del XIAO-ESP32-S3 Sense captura imágenes y las sirve a través de Wi-Fi. El router Wi-Fi transporta estas imágenes al navegador web de tu PC, que las muestra como una transmisión de vídeo. La imagen a continuación ilustra la arquitectura del sistema:

Streaming Video via local Wi-Fi
Transmisión de vídeo vía Wi-Fi local

Ten en cuenta que la transmisión de vídeo no está cifrada ni es segura, pero solo será visible en una URL dentro de tu red Wi-Fi local, por ejemplo 192.168.2.40/stream. Solo alguien con acceso a tu red Wi-Fi podrá ver la transmisión de vídeo.

Código para un servidor de transmisión de vídeo con XIAO-ESP32-S3-Sense

El Getting Started Wiki by Seeed Studio para XIAO-ESP32-S3-Sense ofrece mucha información sobre la placa y también tiene código de ejemplo para un servidor de transmisión de vídeo. Sin embargo, ese código es más complejo que el que verás a continuación.

La simplificación se debe en gran parte a la esp32cam librería, que puedes instalar a través del Library Manager en el Arduino IDE. Solo busca «esp32cam» y pulsa INSTALL. La imagen a continuación muestra la instalación completada:

esp32cam library installed via Library Manager
librería esp32cam instalada vía Library Manager

A continuación encontrarás el código completo para el servidor de transmisión de vídeo, que usa la esp32cam librería. Échale un vistazo rápido y luego discutiremos los detalles:

#include "WebServer.h"
#include "WiFi.h"
#include "esp32cam.h"

const char* WIFI_SSID = "SSID";
const char* WIFI_PASS = "PASSWORD";
const char* URL = "/stream";
const auto RESOLUTION = esp32cam::Resolution::find(800, 600);
const int FRAMERATE = 10;

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::XiaoSense);
  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();
}

Librerías

El sketch comienza incluyendo las librerías necesarias:

#include "WebServer.h"
#include "WiFi.h"
#include "esp32cam.h"

Estas librerías habilitan la funcionalidad del servidor HTTP (WebServer.h), la conectividad Wi-Fi (WiFi.h) y el control de la cámara usando la librería esp32cam.

Constantes

A continuación, definimos constantes para la configuración de Wi-Fi y la cámara:

const char* WIFI_SSID = "SSID";
const char* WIFI_PASS = "PASSWORD";
const char* URL = "/stream";
const auto RESOLUTION = esp32cam::Resolution::find(800, 600);
const int FRAMERATE = 10;

Las variables WIFI_SSID y WIFI_PASS almacenan las credenciales de la red Wi-Fi. Deberás reemplazar SSID y PASSWORD con los datos reales de tu red Wi-Fi.

LaURLes la ruta en la que se servirá la transmisión de vídeo. Puedes cambiarla por lo que quieras. Por ejemplo, «/video» o «/frontdoor», solo asegúrate de mantener la barra (‘/’) al principio.

La RESOLUTION establece la resolución deseada para la cámara. A continuación tienes una lista de los valores posibles para la resolución de la cámara, aunque dependiendo de la cámara no todos pueden funcionar:

  • 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

La variable FRAMERATE define cuántos frames por segundo se enviarán al cliente. Esto te permite ralentizar la transmisión de vídeo y evitar el sobrecalentamiento de la placa. Si configuras una tasa de frames demasiado alta, se limitará automáticamente a lo que el ESP32 puede entregar para la resolución de cámara específica.

Objetos

La siguiente línea crea el objeto servidor HTTP que escucha en el puerto 80. Ese es nuestro servidor web que proporciona la transmisión de vídeo.

WebServer server(80);

handleStream

La función handleStream() gestiona la transmisión de vídeo cada vez que un cliente accede a la ruta /stream:

void handleStream() {
  static char head[128];
  WiFiClient client = server.client();

Esta línea obtiene el cliente actual conectado al servidor. Luego se prepara la respuesta:

server.sendContent("HTTP/1.1 200 OK\r\n"
                   "Content-Type: multipart/x-mixed-replace; "
                   "boundary=frame\r\n\r\n");

Esta cabecera indica al navegador que recibirá una transmisión MJPEG multipartida, donde cada parte está separada por un límite llamado frame.

Dentro del bucle, la función primero captura un frame de la cámara:

  while (client.connected()) {
    auto frame = esp32cam::capture();

Si se captura un frame con éxito, se construye una cabecera que describe la imagen JPEG y se envía al cliente:

    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");
    }

initCamera

La función initCamera() configura y arranca la cámara:

void initCamera() {
  using namespace esp32cam;
  Config cfg;
  cfg.setPins(pins::XiaoSense);
  cfg.setResolution(RESOLUTION);
  cfg.setBufferCount(2);
  cfg.setJpeg(80);
  Camera.begin(cfg);
}

Primero, se crea un objeto Config. La función setPins configura los pines de la cámara basándose en la placa XIAO-ESP32-S3 Sense. Consulta la pin configurations de otras placas soportadas.

setResolution define la resolución a usar, mientras que setBufferCount determina cuántos buffers de imagen se usan internamente, lo que puede ayudar a conseguir tasas de frames más rápidas.

La función setJpeg establece la calidad de compresión JPEG entre 0 y 100. 80 es un buen equilibrio entre calidad y tamaño. 90 ofrece mejor calidad pero una reducción menor en el tamaño de la imagen. Para vídeo más rápido puedes reducir la resolución y la compresión JPEG, pero obviamente obtendrás imágenes más pequeñas y de menor calidad.

Finalmente, Camera.begin(cfg) inicializa la cámara con estas configuraciones.

initWifi

La función initWifi() conecta la placa XIAO-ESP32-S3 Sense a la red Wi-Fi especificada:

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) desactiva la escritura de las credenciales en la memoria flash, lo que acelera la reconexión. El dispositivo se configura en modo estación (WIFI_STA), y trata de conectarse al Wi-Fi usando las credenciales dadas.

Una vez conectado, la dirección IP y la ruta de la transmisión se imprimen en el monitor serial. Necesitarás copiar y pegar esta URL impresa en la barra de direcciones de tu navegador para ver la transmisión de vídeo. La URL real dependerá de tu placa, pero puedes cambiar el sufijo «stream». En mi placa, veo la siguiente URL en el Monitor Serial:

Streaming URL printed to Serial Monitor
URL de transmisión impresa en el Monitor Serial

Por lo tanto, copio «http://192.168.2.40/stream» en la barra de direcciones de mi navegador Chrome para acceder al vídeo.

initServer

La función initServer() asocia la ruta de transmisión con el manejador y arranca el servidor:

void initServer() {
  server.on(URL, handleStream);
  server.begin();
}

Esto mapea cualquier petición a /streama la función handleStream(), y luego inicia el servidor.

setup

La función setup() inicia la comunicación serial, conecta al Wi-Fi, inicializa la cámara y configura el servidor web:

void setup() {
  Serial.begin(115200);
  initWifi();
  initCamera();
  initServer();
}

loop

Finalmente, la función loop() gestiona continuamente las peticiones HTTP entrantes:

void loop() {
  server.handleClient();
}

Esta línea permite que el XIAO-ESP32-S3 Sense responda a las solicitudes de los clientes invocando cualquier manejador registrado como handleStream().

En conjunto, este código crea un servidor de transmisión MJPEG simple pero efectivo que puede ser accedido desde cualquier navegador web dentro de la misma red, proporcionando una transmisión en vivo desde la cámara del XIAO-ESP32-S3 Sense.

Para descargar ese código a tu XIAO-ESP32-S3 Sense, selecciona la placa XIAO_ESP32S3 y pulsa el botón de descarga.

Select XIAO_ESP32S3 as board
SeleccionaXIAO_ESP32S3como placa

Si necesitas más ayuda con esto, echa un vistazo al Getting started with XIAO-ESP32-S3-Sense tutorial.

Conclusiones

En este tutorial aprendiste cómo transmitir vídeo desde un XIAO-ESP32-S3 Sense a través de tu red Wi-Fi local a tu navegador web.

Si quieres detectar objetos en la transmisión de vídeo, echa un vistazo al Object Detection with ESP32-CAM and YOLO tutorial. Está escrito para el ESP32-CAM pero solo requiere un pequeño cambio (cfg.setPins(pins::XiaoSense)) para funcionar con el XIAO-ESP32-S3 Sense.

De forma similar, el Surveillance Camera with ESP32-CAM tutorial te muestra cómo grabar vídeos activados por movimiento en un archivo.

Si tienes alguna pregunta, no dudes en dejarla en la sección de comentarios.

¡Feliz bricolaje ; )