esp32cam-rtsp项目AP模式RTSP移植

esp32cam-rtsp 项目中 rtsp 实时视频流是一个非常重要的功能,但只能使用在 STA 模式(即 ESP32 开发板连接到路由器获取 IP 地址),AP 热点模式下不能使用,下面介绍修订源码,实现 AP 模式支持 RTSP,并且提高访问速度。

一、RTSP 功能概述

1、RTSP 是什么

RTSP(Real-Time Streaming Protocol,实时流传输协议)

  1. 标准:IETF 标准实时流媒体控制协议,只负责「控制」,不负责传输画面数据
  2. 端口:默认 554(你项目里使用的端口);
  3. 定位:像「视频遥控器」,专门用来控制摄像头、NVR 的播放、暂停、拉流、录像;
  4. 配套传输:画面码流(JPEG/H.264/H.265)依靠 RTP 协议打包发送。

两个核心配套协议区分

  1. RTSP:控制信令 客户端 (VLC) ↔ 设备 (ESP32) 之间交互指令:DESCRIBE、SETUP、PLAY、PAUSE、TEARDOWN。
  2. RTP:媒体数据承载 真正装 JPEG / 视频帧的数据包,走 UDP 或 TCP,负责画面传输。

2、RTSP 标准 5 步交互流程

  1. DESCRIBE VLC 询问设备:你支持什么分辨率、编码、帧率、通道地址; ESP32 返回媒体描述(SDP 文本),告知路径 /mjpeg/1
  2. SETUP 协商传输通道:UDP / TCP,分配端口,建立 RTP 收发通道。
  3. PLAY VLC 下发播放指令,ESP32 开始持续抓取摄像头帧,打包 RTP 发送。
  4. 持续传输:RTP 分包推送画面,RTSP 定时保活(OPTIONS)防止断连。
  5. TEARDOWN 关闭播放器,发送断开指令,ESP32 停止推流、释放缓冲区。

3、两种传输模式

1)UDP(默认)

  • 优点:延迟极低、开销小;
  • 缺点:无重传,WiFi 弱网丢包 → 花屏、卡顿、掉帧; ESP32 无线环境极易出现丢包,RTSP 帧率暴跌。

2)TCP(推荐Windows 使用)

RTP 媒体数据嵌入 RTSP 554 端口 TCP 通道,可靠传输、不丢包 ,VLC 参数添加 :rtsp_transport=tcp; 代价:多一层封装,轻微增加延迟,但画面稳定。


4、RTSP/HTTP MJPEG对比

1)HTTP MJPEG(网页 http://192.168.4.1/stream

  • 工作逻辑:浏览器循环 GET 请求,每次返回一整张 JPEG;
  • 无复杂协议封装、无会话管理、无 RTP 分片;
  • 优势:ESP32 负载极低、帧率高、延迟最小;
  • 缺点:只能单客户端、不支持录像、无标准流媒体设备兼容。

2) RTSP(rtsp://192.168.4.1:554/mjpeg/1

  • 优势:标准安防协议,支持 VLC、NVR、监控软件、手机播放器;支持多路客户端、录像、回放控制;
  • 劣势:多层协议封装(RTSP+RTP),CPU/PSRAM 开销更大,同等硬件下帧率低于 HTTP 流。

5、RTSP 典型应用场景

  1. 监控摄像头(海康 / 大华 / ESP32-CAM);
  2. 直播低延迟设备、IP 摄像头;
  3. NVR 网络硬盘录像机存储录像;
  4. 专业播放器 VLC、PotPlayer、安防客户端。

6、常用 RTSP 地址格式说明

复制代码
rtsp://[设备IP]:554/[流路径]
rtsp://192.168.4.1:554/mjpeg/1
  • 192.168.4.1:ESP32 AP 热点 IP;
  • 554:RTSP 标准端口;
  • /mjpeg/1:媒体流标识,区分多路摄像头通道。

7、RTSP 常见缺陷

  1. 防火墙容易拦截 554 端口;
  2. 原生不支持浏览器直接播放(Chrome/Edge 不解析 RTSP,只能用 VLC);
  3. 嵌入式 MCU(ESP32)算力有限,RTSP 封装开销会明显降低帧率;
  4. UDP 模式无线环境丢包严重,必须强制 TCP 传输才能稳定。

二、源码移植

1、platformio.ini 环境配置

确认宏写在对应板子环境内,不要写全局:

复制代码
[env:esp32cam_s3_wroom_n16r8]
platform = espressif32
board = esp32cam_s3_wroom_n16r8
framework = arduino
build_flags =
    -Ofast
    -D 'BOARD_NAME="${this.board}"'
    -D 'CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE'
    -D 'IOTWEBCONF_PASSWORD_LEN=64'
    # RTSP核心开关,必须在当前env内
    -DENABLE_RTSP
    -DBOARD_HAS_PSRAM
    -DCONFIG_SPIRAM
    -DCONFIG_SPIRAM_MODE_OCT
    -DCONFIG_SPIRAM_SPEED_80M
board_build.arduino.memory_type = qio_opi
board_build.psram = 8MB
monitor_speed = 115200
monitor_filters = log2file, time, no_color, esp32_exception_decoder

注:配合 ini 文件最后 2 行的串口配置,在项目的 main.cpp 文件,setup( )中注释 //Serial.setDebugOutput(true);语句,log_i 调试信息才会串口输出。

2、start_rtsp_server 分析

项目源码的 main.cpp 主文件中, setup() 中不能调用启动start_rtsp_server 函数,否则程序运行会崩溃。

复制代码
assert failed: tcpip_send_msg_wait_sem IDF/components/lwip/lwip/src/api/tcpip.c:455 (Invalid mbox)

崩溃原理

LWIP TCP/IP 内核消息队列(mbox)未初始化,你在 setup() 直接调用 start_rtsp_server() 创建 WiFiServer(RTSP 底层依赖),此时:

  1. WiFi AP 网络栈、lwip tcpip 任务还未完全初始化完成;
  2. rtsp_server 构造函数内部执行 WiFiServer::begin(554),底层调用 netconn_new 操作未就绪的 TCPIP 消息队列,触发断言崩溃、设备自动重启。

堆栈链路印证

复制代码
setup() -> on_connected() -> start_rtsp_server() -> new rtsp_server()
    -> WiFiServer::begin() -> lwip_socket -> netconn_new -> tcpip_send_msg_wait_sem 断言失败

原设计把 start_rtsp_server 放在 on_connected WiFi 连接回调,是为了等待网络栈完全就绪,强行在 setup 提前调用,网络层未就绪直接崩溃。

3、正确启动 RTSP 服务

延时延后启动 RTSP,等待 AP 网络初始化完成(AP 模式专用)

项目源码的 main.cpp,不在 setup 直接调用on_connected(),改用loop( )中 延时延迟启动,给 LWIP/AP 栈充足初始化时间:

全局增加标志位

复制代码
bool rtsp_started = false;

loop 函数内延时执行

复制代码
void loop()
{
  // 等待8秒,确保AP、tcpip、lwip全部初始化完成
  if(!rtsp_started && millis() > 8000 && camera_init_result == ESP_OK)
  {
    log_i("Delay start RTSP after AP init complete");
    start_rtsp_server();
    rtsp_started = true;
  }
  // 原有loop逻辑...
}

优势:不破坏原有回调逻辑,避开网络未就绪时序,不会触发 lwip 断言崩溃。

4、PlatformIO 6.x 命令

复制代码
# 清理当前环境全部缓存(6.x标准语法)
pio run -t clean -e esp32cam_s3_wroom_n16r8
# 完整编译
pio run -e esp32cam_s3_wroom_n16r8
# 烧录固件
pio run -t upload -e esp32cam_s3_wroom_n16r8
# 重新打开串口监控查看RTSP启动日志
pio device monitor -e esp32cam_s3_wroom_n16r8

5、调试日志分析

RTSP 服务成功启动(核心正常信息)

复制代码
[  8001][I][main.cpp:447] loop(): Delay start RTSP after AP init complete
[  8007][V][main.cpp:305] start_rtsp_server(): start_rtsp_server
[  8013][I][main.cpp:306] start_rtsp_server(): start_rtsp_server-----------tony
[  8028][I][rtsp_server.cpp:9] rtsp_server(): Starting RTSP server
[ r::WiFiServer(port=554, ...)

说明:

  1. 延时方案生效,等待 8 秒后正常执行 start_rtsp_server()
  2. RTSP 服务实例创建成功,554 端口 WiFiServer 正常开启;
  3. 网页后台 RTSP sessions 不再显示 RTSP server disabled,会显示数字 0
  4. 现在 Windows 连接热点后,VLC 可正常拉流 rtsp://192.168.4.1:554/mjpeg/1

mDNS 注册失败(不影响 RTSP 核心功能)

复制代码
[  8034][E][ESPmDNS.cpp:148] addService(): Failed adding service

设备启动时 mDNS 服务初始化晚于 RTSP 注册调用,注册 rtsp 服务超时失败;

不影响 554 端口 RTSP 拉流,只是无法通过域名 esp32cam.local 访问;

纯 IP 访问完全不受干扰,可忽略该报错。

三、运行测试

1、连接热点

你的 ESP32-S3 当前是AP 热点模式 ,IP 为192.168.4.1,Windows11 电脑必须:

  1. 无线连接 ESP32-CAM 发射的 WiFi 热点(名称 ESP32-CAM-xxxx);

  2. 不要连家用路由器 WiFi,否则网段不通(家用路由一般是 192.168.1.x,和 192.168.4.x 隔离);

  3. 先测试网络连通:按下 Win+R 输入 cmd,执行 cmd

    ping 192.168.4.1

能收到回复代表网络正常;请求超时 = WiFi 连错。


2、RTSP 使用

VLC 媒体播放器(最推荐,免费开源,完美兼容 MJPEG-RTSP)

  1. 官网下载安装 VLC Media Player(Windows/Linux)

  2. 打开 VLC,顶部菜单:媒体 → 打开网络串流 (快捷键 Ctrl+N

  3. 在「请输入网络 URL」粘贴完整地址: plaintext

    rtsp://192.168.4.1:554/mjpeg/1

  4. 优化低延迟(解决卡顿 / 黑屏): 点击「显示更多选项」,将缓存 改为 100(单位 ms); 编辑选项里添加传输参数:rtsp_transport=tcp

  5. 点击「播放」即可实时显示画面。

VLC打开网络串流

填入RTSP地