现有功能更完善的服务端视频方案。
开源地址:https://gitcode.net/qq_26700087/lightcam
功能更全的esp32监控
本方案为esp32cam 服务端 浏览器 三端联合使用。将服务端部署在公网即可远程使用,没有远程需求,可以直接在局域网使用。代码无需修改。
本文取缔了esp32cam自身运行http服务的相关逻辑,使得esp32cam只负责不停拍照片发给服务端,从而减少esp32cam的压力,提升了其视频流畅度。
本文代码开源地址:https://gitcode.net/qq_26700087/simpleVideoServer,该项目的比当前文章更新,更加流畅,并且支持合宙ESP32S3。如果使用本文的代码,则使用本文提供链接中的发行版文件。使用该项目最新代码,请使用该项目的页面提供的下载服务端链接下载服务端发行版
一种较为流畅的esp32cam远程视频方案
物料 | 说明 |
---|---|
esp32cam开发板 | esp32cam,本人是使用其自带摄像头,代码仅仅在其自带摄像头下测试 |
一台装有windows或者linux操作系统的计算机 | 用于运行服务端 |
USB转TTL模块/或底座 | 用于烧录/串口监控 |
杜邦线若干 | 用于io0接地/使用底座烧录不需要 |
鄙人无MacOs系统PC,未对MacOS进行测试。但服务端由java编写,自行下载macOS版本的jdk17,运行服务端,理论上不会有问题
也可以将java源代码重新编译,甚至移植到安卓App上。
本文以windows系统为例,使用安信可家esp32cam
模块 和安信可家USB转TTL CP2012模块
。
本文以ardunio 框架开发,你可以选择 ardunio ide 编译和烧录
或者platformio(基于vs code/clion)新建项目选择 以ardunio framework新建。
打开菜单 -> 文件 -> 首选项
在附加开发板管理器网址中追加一行
https://dl.espressif.com/dl/package_esp32_index.json
最近出现了下面这个地址,这个是esp32 的2.0环境,一些新特性需要,可能不需要上方的那个json。
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_dev_index.json
在 工具 -> 开发板 -> 开发板管理器里 搜索 esp32
点击进行安装。
此处可能需要把dns修改为腾讯或者阿里公共dns,才容易成功。
选择esp32cam
新建项目找到 AI Thinker ESP32-CAM
,则选择了开发板。框架选择 ardunio。若没有初始化esp32环境,会自动下载,同样建议修改dns。
新建后生成的ini文件如下(串口相关设置需要手动添加)
[env:esp32cam]
platform = espressif32
board = esp32cam
framework = arduino
upload_speed= 115200
upload_port = COM3
monitor_speed= 115200
monitor_port = COM3
存在多个文件和服务端相关代码,点此跳转
引导方面本文更加详细。可先参考本文。
esp32cam代码共两个文件。也可以合成一个。
表示esp32cam相关GPIO引脚定义
#ifndef AI_THINKER_32_CAM_META
#define AI_THINKER_32_CAM_META
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#endif
在ardunio ide里无需考虑该文件名,而只是把该文件内容复制到你的.ino
文件中。
请按照具体情况修改wifi的ssid和密码,一般可以使用你pc运行服务端,可以将PC的ip填写到以下源文件host
变量的值中。
#include
#include
#include "esp_camera.h"
#define CAMERA_MODEL_AI_THINKER
#include "ai_thinker_esp32_cam_meta.h"
char* ssid = "test0";
const char* passwd = "12345687";
const char* host = "192.168.137.1";
WiFiClient streamSender;
void connectWifi(const char* ssid, const char* passphrase) {
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, passphrase);
Serial.println("connecting to router... ");
//等待wifi连接成功
while (WiFi.status() != WL_CONNECTED) {
Serial.print(".");
delay(500);
}
Serial.print("\nWiFi connected, local IP address:");
Serial.println(WiFi.localIP());
}
void setup() {
Serial.begin(115200);
Serial.setDebugOutput(true);
while (!Serial) {
/* code */
}
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if (psramFound()) {
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
// camera init
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
return;
}
Serial.println("get sensor ");
sensor_t* s = esp_camera_sensor_get();
// drop down frame size for higher initial frame rate
s->set_framesize(s, FRAMESIZE_VGA);
connectWifi(ssid, passwd);
Serial.println("connect stream channel");
if (!streamSender.connect(host, 8004)) {
Serial.println("connect stream channel failed");
}
streamSender.setNoDelay(true);
// 发送mac地址作为设备序列号,用于摄像头频道号
uint8_t mac[6];
WiFi.macAddress(mac);
char macStr[12] = {0};
sprintf(macStr, "%02X%02X%02X%02X%02X%02X", mac[0], mac[1], mac[2], mac[3],
mac[4], mac[5]);
Serial.println("sprint mac ");
streamSender.print(String(macStr));
streamSender.flush();
}
void loop() {
camera_fb_t* fb = NULL;
size_t len = 0;
Serial.println("do loop");
uint8_t end[5] = {'j', 'p', 'e', 'g', '\n'};
while (true) {
fb = esp_camera_fb_get();
if (!fb) {
Serial.println("Camera capture failed");
return;
}
len = fb->len;
streamSender.write(fb->buf, len);
streamSender.write(end, 5);
streamSender.flush();
esp_camera_fb_return(fb);
}
}
查看PC的ip的办法
按win + R 输入cmd
按enter打开控制台
输入 ipconfig
回车,找到有ipv4地址的那一行。如果有多个适配器,大概率需要自己确定和无线路由器所在同一网络的ip。
一般wifi连接则是网卡名带 无线适配器,而路由器网线直连则自己抉择。
USB转TTL模块引脚 | esp32cam引脚 |
---|---|
5V | 5V |
GND | GND |
TXD | U0R |
RXD | U0T |
当上载控制台出现连接某某com口,请尽快连接IO0和GND,再按RST。
使用烧录底座将esp32cam安上底座,则无需考虑针脚连接具体如何。
鄙人不知烧录底座是否可以串口监控,使用USB转TTL模块时,在烧录完成后,断开IO0与GND的连接,再按RST重启esp32cam则可以查看串口打印,但此时没有运行服务端SimpleVideoServer。
根据自己需要选择以下任意方式运行服务端
下载 windows服务端发行版
解压之后,进入对应目录点击run.bat文件启动服务器。
下载linux服务端发行版
需要unzip或p7zip等可以解压zip的应用
运行
unzip SimpleVideoSever_linux.zip
cd linux_release/
sh run.sh
发行版内部仅仅是一些java17 版本的class文件和jre以及启动脚本,你可以使用任意其它的jre17运行这些class文件。并非需要发行版。
访问视频服务
新增了频道功能,也就是说每个摄像头处在不同频道,访问不同的摄像头需要不同的地址。
如鄙人执行的服务端日志打印含有esp32Cam接入的后的相关打印如下:
D:\Users\immor\idea\SimpleVideoServer\out\win_release>.\jre\bin\java -classpath SimpleVideoServer org.btik.server.video.Main
bio video server started
bio Device Channel started
new channel:
http://127.0.0.1:8003/video/441793EE3C08
http://192.168.0.116:8003/video/441793EE3C08
http://192.168.137.1:8003/video/441793EE3C08
start /192.168.137.234:53051
每接入一个esp32Cam会新建一个频道,在new channel:
的打印后会出现,相关可以访问视频流的地址。
你可以在本机,或者局域网的其他设备访问。
部署在云服务器的同学把端口打开后,把内网ip替换成公网ip,或者域名即可。
关于如何把视频节目嵌入其它网页
如果你擅长web开发,或者不喜欢在多个窗口查看多个摄像头可以参考以下方法增加自己的内容。
本视频http请求是允许跨域的,若希望在自己的网页里面加入本服务端提供esp32Cam视频窗口,
其实不用html的 iframe
标签,img
标签即可。
比如以下html代码,新建一个文件比如a.html
复制以下内容,根据实际情况,替换img
标签src
属性的内容。
DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>直播间title>
<style>
.videoContainer{
display: inline-block;
}
style>
head>
<body>
<div style="padding: 0;margin:30px auto; width: 1300px">
<div class="videoContainer">
<img src="http://127.0.0.1:8003/video/441793EE3C08">
div>
<div class="videoContainer">
<img src="http://127.0.0.1:8003/video/58BF2581F024">
div>
div>
body>
html>
以上是我的两个esp32Cam的视野,效果如下:
也就是说,你可以把该项目植入任何其它可以用到web前端的项目。通过查询在线设备,可以动态打开每个摄像头的视频。
一般无需修改,但提供改法。后续此处可能会有变化,可以跟随该开源项目SimpleVideoSever具体描述。
light-video.properties
里面含有三个配置
http.port=8003
http.clients.limit=10
stream.port=8004
http.port 为http的端口。
http.clients.limit 摄像头在线接入限制数。本意是想限制客户端参与的数量故名为http.clients.limit,实际的实现是限制了摄像头的数量
stream.port esp32cam像服务端发送照片的端口,在本项目中使用该默认端口,如果需要修改,一并修改esp32cam代码中连接的端口。一般无需修改。
使用远程服务器如云服务器同学则无需额外指导。注意本服务端毫不安全,没有任何安全机制,在公网使用不宜长久暴露服务端口。