Neste tutorial, vais aprender a transmitir vídeo a partir de um Seeed Studio XIAO-ESP32-S3 Sense através da tua rede Wi-Fi local para o teu navegador Web. Isto permite-te construir o teu próprio sistema de câmaras de vigilância sem fios que podes monitorizar a partir do teu computador.
Se nunca usaste o XIAO-ESP32-S3 Sense antes, dá uma vista de olhos ao Getting started with XIAO-ESP32-S3-Sense tutorial primeiro, que te ajuda a começar com a placa.
Peças Necessárias
Obviamente, vais precisar de uma placa XIAO-ESP32-S3 Sense da Seeed Studio para experimentar os exemplos de código. Nota que a placa pode aquecer bastante, por exemplo, ao transmitir vídeo com uma alta taxa de frames. Recomendo que coloques um pequeno Heatsink na parte de trás da placa (ver a peça listada abaixo).

Seeed Studio XIAO ESP32 S3 Sense

Cabo USB C

Pequeno Dissipador 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.
Transmissão de Vídeo
Neste projeto, vamos implementar um servidor de streaming de vídeo que corre no XIAO-ESP32-S3 Sense. A câmara do XIAO-ESP32-S3 Sense captura imagens e serve-as via Wi-Fi. O router Wi-Fi transporta estas imagens para o navegador Web no teu PC, que as exibe como um fluxo de vídeo. A imagem abaixo ilustra a arquitetura do sistema:

Nota que o fluxo de vídeo não é encriptado nem seguro, mas será visível apenas numa URL dentro da tua rede Wi-Fi local, por exemplo 192.168.2.40/stream. Só quem tiver acesso à tua rede Wi-Fi poderá ver o fluxo de vídeo.
Código para um Servidor de Streaming de Vídeo com XIAO-ESP32-S3-Sense
O Getting Started Wiki by Seeed Studio para XIAO-ESP32-S3-Sense fornece muita informação sobre a placa e também tem código de exemplo para um Servidor de Streaming de Vídeo. No entanto, esse código é mais complexo do que o código abaixo.
A simplificação deve-se em grande parte à biblioteca esp32cam, que podes instalar via Library Manager no Arduino IDE. Basta procurar por “esp32cam” e carregar em INSTALL. A imagem abaixo mostra a instalação concluída:

Abaixo encontras o código completo para o servidor de streaming de vídeo, que usa a biblioteca esp32cam. Dá uma vista de olhos rápida e depois discutimos os detalhes:
#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();
}
Bibliotecas
O sketch começa por incluir as bibliotecas necessárias:
#include "WebServer.h" #include "WiFi.h" #include "esp32cam.h"
Estas bibliotecas permitem a funcionalidade de servidor HTTP (WebServer.h), conectividade Wi-Fi (WiFi.h) e controlo da câmara usando a biblioteca esp32cam.
Constantes
De seguida, definimos constantes para as configurações de Wi-Fi e da 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;
As variáveis WIFI_SSID e WIFI_PASS guardam as credenciais da rede Wi-Fi. Terás de substituir SSID e PASSWORD pelos dados reais da tua rede Wi-Fi.
A variável URL é o caminho onde o fluxo de vídeo será servido. Podes alterar para o que quiseres. Por exemplo, “/video” ou “/frontdoor”, só certifica-te de manter a barra (‘/’) no início.
A variável RESOLUTION define a resolução desejada para a câmara. Abaixo está uma lista dos valores possíveis para a resolução da câmara, embora dependendo da câmara nem todos possam 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
A variável FRAMERATE define quantos frames por segundo serão enviados ao cliente. Isto permite abrandar o fluxo de vídeo e evitar o sobreaquecimento da placa. Se definires a taxa de frames demasiado alta, será automaticamente limitada ao que o ESP32 consegue entregar para a resolução da câmara específica.
Objetos
A linha seguinte cria o objeto do servidor HTTP que escuta na porta 80. Esse é o nosso servidor web que fornece o fluxo de vídeo.
WebServer server(80);
handleStream
A função handleStream() trata o fluxo de vídeo sempre que um cliente acede ao caminho /stream:
void handleStream() {
static char head[128];
WiFiClient client = server.client();
Esta linha obtém o cliente atual ligado ao servidor. A resposta é então preparada:
server.sendContent("HTTP/1.1 200 OK\r\n"
"Content-Type: multipart/x-mixed-replace; "
"boundary=frame\r\n\r\n");
Este cabeçalho informa o navegador que vai receber um fluxo MJPEG multipartido, onde cada parte é separada por um limite chamado frame.
Dentro do loop, a função primeiro captura um frame da câmara:
while (client.connected()) {
auto frame = esp32cam::capture();
Se um frame for capturado com sucesso, é construído um cabeçalho a descrever a imagem JPEG, e enviado ao 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
A função initCamera() configura e inicia a 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);
}
Primeiro, é criado um objeto Config. A função setPins configura os pinos da câmara com base na placa XIAO-ESP32-S3 Sense. Vê o pin configurations de outras placas suportadas.
setResolution define a resolução a usar, enquanto setBufferCount determina quantos buffers de imagem são usados internamente, o que pode ajudar a obter taxas de frames mais rápidas.
A função setJpeg define a qualidade da compressão JPEG entre 0 e 100. 80 é um bom equilíbrio entre qualidade e tamanho. 90 dá melhor qualidade mas uma redução menor no tamanho da imagem. Para vídeo mais rápido podes reduzir a resolução e a compressão JPEG, mas obviamente obterás imagens menores com qualidade inferior.
Finalmente, Camera.begin(cfg) inicializa a câmara com estas configurações.
initWifi
A função initWifi() liga a placa XIAO-ESP32-S3 Sense à rede 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) desativa a escrita das credenciais na flash, o que acelera a reconexão. O dispositivo é configurado para modo station (WIFI_STA), e tenta ligar-se ao Wi-Fi usando as credenciais fornecidas.
Uma vez ligado, o endereço IP e o caminho do fluxo são impressos no monitor serial. Terás de copiar e colar esta URL impressa na barra de endereços do teu navegador para ver o fluxo de vídeo. A URL real dependerá da tua placa, mas podes alterar o sufixo “stream”. Na minha placa, vejo a seguinte URL no Monitor Serial:

Portanto, copio “http://192.168.2.40/stream” para a barra de endereços do meu navegador Chrome para aceder ao vídeo.
initServer
A função initServer() liga o caminho de streaming ao handler e inicia o servidor:
void initServer() {
server.on(URL, handleStream);
server.begin();
}
Isto mapeia qualquer pedido a /stream para a função handleStream(), e depois inicia o servidor.
setup
A função setup() inicia a comunicação serial, liga ao Wi-Fi, inicializa a câmara e configura o servidor web:
void setup() {
Serial.begin(115200);
initWifi();
initCamera();
initServer();
}
loop
Finalmente, a função loop() trata continuamente os pedidos HTTP recebidos:
void loop() {
server.handleClient();
}
Esta linha permite que o XIAO-ESP32-S3 Sense responda a pedidos dos clientes invocando quaisquer handlers registados, como handleStream().
No total, este código cria um servidor de streaming MJPEG simples mas eficaz que pode ser acedido a partir de qualquer navegador web dentro da mesma rede, fornecendo um feed de câmara ao vivo do XIAO-ESP32-S3 Sense.
Para transferir esse código para o teu XIAO-ESP32-S3 Sense, seleciona a placa XIAO_ESP32S3 e carrega no botão de download.

XIAO_ESP32S3 como placaSe precisares de mais ajuda com isto, dá uma vista de olhos ao Getting started with XIAO-ESP32-S3-Sense tutorial.
Conclusões
Neste tutorial aprendeste a transmitir vídeo de um XIAO-ESP32-S3 Sense através da tua rede Wi-Fi local para o teu navegador Web.
Se quiseres detetar objetos no fluxo de vídeo, vê o Object Detection with ESP32-CAM and YOLO tutorial. Está escrito para o ESP32-CAM mas requer apenas uma pequena alteração (cfg.setPins(pins::XiaoSense)) para funcionar com o XIAO-ESP32-S3 Sense.
De forma semelhante, o tutorial Surveillance Camera with ESP32-CAM mostra como gravar fluxos de vídeo ativados por movimento para um ficheiro.
Se tiveres alguma dúvida, não hesites em deixar nos comentários.
Boas experiências a criar ; )

