Skip to Content

Transmitir Vídeo com ESP32-CAM

Transmitir Vídeo com ESP32-CAM

Neste tutorial, vais aprender a transmitir vídeo de um ESP32-CAM pela tua rede Wi-Fi local para o teu navegador Web. Isto permitirá, por exemplo, construir uma câmara de vigilância sem fios que podes monitorizar a partir do teu computador.

Peças Necessárias

Vais precisar de um ESP32-CAM para experimentar os exemplos de código. Podes obter um ESP32-CAM com um USB-TTL Shield para programação ou um Adaptador FTDI USB-TTL. O Adaptador FTDI USB-TTL é um pouco mais complicado de usar, mas deixa os pinos GPIO facilmente acessíveis. Para este tutorial, recomendo o USB-TTL Shield, mas certifica-te de que escolhes o correto (ver Programming the ESP32-CAM tutorial para detalhes).

ESP32-CAM com USB-TTL Shield

Adaptador FTDI USB-TTL

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 ESP32-CAM. O ESP32-CAM captura imagens e serve-as via Wi-Fi. O router Wi-Fi transporta estas imagens para o navegador Web, que as exibe como um fluxo de vídeo. A imagem abaixo ilustra a configuração:

Transmissão de Vídeo via WiFi local

Note 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.39/stream. Só quem tiver acesso à tua rede Wi-Fi poderá ver o fluxo de vídeo.

Código para o Servidor de Vídeo

O seguinte sketch Arduino configura o servidor de streaming de vídeo que envia um fluxo MJPEG contínuo da câmara ESP32-CAM para qualquer navegador web ligado à mesma rede Wi-Fi.

Para este código, vamos usar a esp32cam biblioteca, que simplifica o controlo da câmara. Podes instalá-la via Library Manager no Arduino IDE. Basta procurar por “esp32cam” e clicar em INSTALL. A imagem abaixo mostra a instalação concluída:

esp32cam library installed via Library Manager
Biblioteca esp32cam instalada via Library Manager

Abaixo encontras o código completo para o servidor de streaming de vídeo. Dá uma vista de olhos rápida e depois discutiremos 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 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();
}

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 o ESP32-CAM (esp32cam.h).

Constantes

De seguida, são definidas algumas constantes:

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

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 FRAMERATE define quantos frames por segundo serão enviados ao cliente. E a RESOLUTION define a resolução desejada para a câmara usando a biblioteca esp32cam.

Aqui 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

Podes imprimir a lista de resoluções da câmara usando a seguinte função:

void printResolutions() {
  Serial.println("Camera resolutions:");
  for (auto res : esp32cam::Camera.listResolutions()) {
    Serial.printf("%dx%d\n", res.getWidth(), res.getHeight());
  }
}

Note que a resolução afeta a taxa máxima de frames. Com uma resolução de 1600×1200 não vais conseguir mais do que cerca de 10 frames por segundo.

Objetos

A linha seguinte cria um objeto 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 de um ciclo, a função 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 que descreve a imagem JPEG:

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

A imagem é enviada ao cliente como JPEG, e depois o ciclo espera brevemente conforme a taxa de frames:

delay(1000 / FRAMERATE);

Note que esta constante FRAMERATE só permite abrandar a taxa de frames abaixo do máximo que o ESP32-CAM pode produzir para a resolução dada. Se quiseres sempre a taxa máxima, basta remover esta linha.

initCamera

A função initCamera() configura e inicia o hardware do ESP32-CAM:

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

Aqui, é criado um objeto Config. A função setPins configura os pinos da câmara com base no layout da placa AiThinker. setResolution define a resolução a usar, enquanto setBufferCount determina quantos buffers de imagem são usados internamente.

A função setJpeg define a qualidade da compressão JPEG. 80 é um bom equilíbrio entre qualidade e tamanho. 90 dá melhor qualidade mas menor redução do tamanho da imagem. Para vídeo mais rápido podes reduzir a resolução e a compressão JPEG, mas obviamente terás imagens menores e de qualidade inferior.

Finalmente, Camera.begin(cfg) inicializa a câmara com estas definições.

initWifi

A função initWifi() liga o ESP32-CAM à 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 em modo station mode (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 no navegador para ver o fluxo de vídeo. A URL real depende do teu ESP32-CAM, mas podes alterar o sufixo “stream”. No meu caso, vejo a seguinte URL no Monitor Serial:

Streaming URL printed to Serial Monitor
URL de Streaming impressa no Monitor Serial

Portanto, copio “http://192.168.2.39/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() corre uma vez no arranque:

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

Inicia a comunicação serial, liga ao Wi-Fi, inicializa a câmara e configura o servidor web.

loop

Finalmente, a função loop() trata continuamente os pedidos HTTP recebidos:

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

Esta linha permite ao ESP32-CAM responder a pedidos dos clientes invocando os handlers registados, como handleStream().

No total, este código cria um servidor de streaming MJPEG simples mas eficaz, acessível a partir de qualquer navegador na mesma rede, fornecendo um feed de vídeo ao vivo do ESP32-CAM.

Para transferir este código para o teu módulo ESP32-CAM, seleciona a placa AI Thinker ESP32-CAM e depois coloca o ESP32-CAM em modo de download.

Select AI Thinker ESP32-CAM  as board
Seleciona AI Thinker ESP32-CAM como placa

Se precisares de ajuda com isto, consulta o Programming the ESP32-CAM tutorial.

Conclusões

Neste tutorial aprendeste a transmitir vídeo de um ESP32-CAM pela tua rede Wi-Fi local para o teu navegador Web.

Se quiseres detetar objetos no fluxo de vídeo, dá uma vista de olhos ao nosso Object Detection with ESP32-CAM and YOLO tutorial. Se quiseres construir um sistema de vigilância ativado por movimento, o tutorial Motion Activated ESP32-CAM pode ser útil.

Também vê o tutorial More GPIO pins for ESP32-CAM, se precisares de mais pinos GPIO para controlar o teu sistema de vigilância. Alternativamente, podes considerar uma placa diferente com mais GPIOs, como a XIAO-ESP32-S3-Sense ou a ESP32-WROVER CAM.

Por fim, podes querer ligar o LED flash do ESP32-CAM se usares a câmara num ambiente escuro. Consulta o tutorial Control ESP32-CAM Flash LED para mais detalhes.

Se tiveres alguma dúvida, não hesites em deixar nos comentários.

Boas experiências ; )