esp32cam 服务端远程视频方案
说明
- 本方案为esp32cam 服务端 浏览器 三端联合使用。将服务端部署在公网即可远程使用,没有远程需求,可以直接在局域网使用。代码无需修改。
- 本文取缔了esp32cam自身运行http服务的相关逻辑,使得esp32cam只负责不停拍照片发给服务端,从而减少esp32cam的压力,提升了其视频流畅度。
- 本文代码开源地址:https://gitcode.net/qq_26700087/simpleVideoServer,**该项目的比当前文章更新,更加流畅,并且支持合宙ESP32S3。如果使用本文的代码,则使用本文提供链接中的发行版文件。使用该项目最新代码,请使用该项目的页面提供的下载服务端链接下载服务端发行版**
#mermaid-svg-p6MVOztAqoknqrsn {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-p6MVOztAqoknqrsn .error-icon{fill:#552222;}#mermaid-svg-p6MVOztAqoknqrsn .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-p6MVOztAqoknqrsn .edge-thickness-normal{stroke-width:2px;}#mermaid-svg-p6MVOztAqoknqrsn .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-p6MVOztAqoknqrsn .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-p6MVOztAqoknqrsn .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-p6MVOztAqoknqrsn .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-p6MVOztAqoknqrsn .marker{fill:#333333;stroke:#333333;}#mermaid-svg-p6MVOztAqoknqrsn .marker.cross{stroke:#333333;}#mermaid-svg-p6MVOztAqoknqrsn svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-p6MVOztAqoknqrsn .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-p6MVOztAqoknqrsn .cluster-label text{fill:#333;}#mermaid-svg-p6MVOztAqoknqrsn .cluster-label span{color:#333;}#mermaid-svg-p6MVOztAqoknqrsn .label text,#mermaid-svg-p6MVOztAqoknqrsn span{fill:#333;color:#333;}#mermaid-svg-p6MVOztAqoknqrsn .node rect,#mermaid-svg-p6MVOztAqoknqrsn .node circle,#mermaid-svg-p6MVOztAqoknqrsn .node ellipse,#mermaid-svg-p6MVOztAqoknqrsn .node polygon,#mermaid-svg-p6MVOztAqoknqrsn .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-p6MVOztAqoknqrsn .node .label{text-align:center;}#mermaid-svg-p6MVOztAqoknqrsn .node.clickable{cursor:pointer;}#mermaid-svg-p6MVOztAqoknqrsn .arrowheadPath{fill:#333333;}#mermaid-svg-p6MVOztAqoknqrsn .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-p6MVOztAqoknqrsn .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-p6MVOztAqoknqrsn .edgeLabel{background-color:#e8e8e8;text-align:center;}#mermaid-svg-p6MVOztAqoknqrsn .edgeLabel rect{opacity:0.5;background-color:#e8e8e8;fill:#e8e8e8;}#mermaid-svg-p6MVOztAqoknqrsn .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-p6MVOztAqoknqrsn .cluster text{fill:#333;}#mermaid-svg-p6MVOztAqoknqrsn .cluster span{color:#333;}#mermaid-svg-p6MVOztAqoknqrsn div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-p6MVOztAqoknqrsn :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}
帧
mjpeg视频流
esp32cam
SimpleVideoServer
浏览器
一种较为流畅的esp32cam远程视频方案
您需要准备
物料说明esp32cam开发板esp32cam,本人是使用其自带摄像头,代码仅仅在其自带摄像头下测试一台装有windows或者linux操作系统的计算机用于运行服务端USB转TTL模块/或底座用于烧录/串口监控杜邦线若干用于io0接地/使用底座烧录不需要
鄙人无MacOs系统PC,未对MacOS进行测试。但服务端由java编写,自行下载macOS版本的jdk17,运行服务端,理论上不会有问题
也可以将java源代码重新编译,甚至移植到安卓App上。
本文以windows系统为例,使用安信可家
esp32cam
模块 和安信可家
USB转TTL CP2012模块
。
烧录esp32cam
本文以ardunio 框架开发,你可以选择 ardunio ide 编译和烧录
或者platformio(基于vs code/clion)新建项目选择 以ardunio framework新建。
ardunio ide 准备esp32cam环境
1.追加附加板地址
打开菜单 -> 文件 -> 首选项
在附加开发板管理器网址中追加一行
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
2.安装esp32环境
在 工具 -> 开发板 -> 开发板管理器里 搜索
esp32
点击进行安装。
此处可能需要把dns修改为腾讯或者阿里公共dns,才容易成功。
3.新建项目
选择esp32cam
platformio 准备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代码共两个文件。也可以合成一个。
文件 ai_thinker_esp32_cam_meta.h
表示esp32cam相关GPIO引脚定义
#ifndefAI_THINKER_32_CAM_META#defineAI_THINKER_32_CAM_META#definePWDN_GPIO_NUM32#defineRESET_GPIO_NUM-1#defineXCLK_GPIO_NUM0#defineSIOD_GPIO_NUM26#defineSIOC_GPIO_NUM27#defineY9_GPIO_NUM35#defineY8_GPIO_NUM34#defineY7_GPIO_NUM39#defineY6_GPIO_NUM36#defineY5_GPIO_NUM21#defineY4_GPIO_NUM19#defineY3_GPIO_NUM18#defineY2_GPIO_NUM5#defineVSYNC_GPIO_NUM25#defineHREF_GPIO_NUM23#definePCLK_GPIO_NUM22#endif
文件main.cpp
在ardunio ide里无需考虑该文件名,而只是把该文件内容复制到你的
.ino
文件中。
请按照具体情况修改wifi的ssid和密码,一般可以使用你pc运行服务端,可以将PC的ip填写到以下源文件
host
变量的值中。
#include<Arduino.h>#include<WiFi.h>#include"esp_camera.h"#defineCAMERA_MODEL_AI_THINKER#include"ai_thinker_esp32_cam_meta.h"char* ssid ="test0";constchar* passwd ="12345687";constchar* host ="192.168.137.1";
WiFiClient streamSender;voidconnectWifi(constchar* ssid,constchar* 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());}voidsetup(){
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();}voidloop(){
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模块时接线
USB转TTL模块引脚esp32cam引脚5V5VGNDGNDTXDU0RRXDU0T
当上载控制台出现连接某某com口,请尽快连接IO0和GND,再按RST。
使用烧录底座将esp32cam安上底座,则无需考虑针脚连接具体如何。
串口监控
鄙人不知烧录底座是否可以串口监控,使用USB转TTL模块时,在烧录完成后,断开IO0与GND的连接,再按RST重启esp32cam则可以查看串口打印,但此时没有运行服务端SimpleVideoServer。
下载和运行服务端
根据自己需要选择以下任意方式运行服务端
- 下载 windows服务端发行版解压之后,进入对应目录点击run.bat文件启动服务器。
- 下载linux服务端发行版需要unzip或p7zip等可以解压zip的应用运行
unzip SimpleVideoSever_linux.zipcd 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.Mainbio video server startedbio Device Channel startednew channel:http://127.0.0.1:8003/video/441793EE3C08http://192.168.0.116:8003/video/441793EE3C08http://192.168.137.1:8003/video/441793EE3C08start /192.168.137.234:53051
每接入一个esp32Cam会新建一个频道,在new channel:
的打印后会出现,相关可以访问视频流的地址。你可以在本机,或者局域网的其他设备访问。部署在云服务器的同学把端口打开后,把内网ip替换成公网ip,或者域名即可。 - 关于如何把视频节目嵌入其它网页如果你擅长web开发,或者不喜欢在多个窗口查看多个摄像头可以参考以下方法增加自己的内容。本视频http请求是允许跨域的,若希望在自己的网页里面加入本服务端提供esp32Cam视频窗口,其实不用html的
iframe
标签,img
标签即可。比如以下html代码,新建一个文件比如a.html
复制以下内容,根据实际情况,替换img
标签src
属性的内容。<!DOCTYPEhtml><htmllang="en"><head><metacharset="UTF-8"><title>直播间</title><style>.videoContainer{display: inline-block;}</style></head><body><divstyle="padding: 0;margin:30px auto;width: 1300px"><divclass="videoContainer"><imgsrc="http://127.0.0.1:8003/video/441793EE3C08"></div><divclass="videoContainer"><imgsrc="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代码中连接的端口。一般无需修改。
使用远程服务器如云服务器同学则无需额外指导。注意本服务端毫不安全,没有任何安全机制,在公网使用不宜长久暴露服务端口。
版权归原作者 云逸之 所有, 如有侵权,请联系我们删除。