
GStreamer RTSP、调试、部署与综合项目专栏:GStreamer C++ 从零到工程实战· 第 15 篇 / 共 17 篇从 RTSP/RTP、Jitter 与低延迟讲到 GST_DEBUG、Pipeline 图、插件注册表、Windows 部署、性能优化和可恢复的多源视频综合项目。第 18 课:RTSP / RTP / Jitter / 低延迟文件播放的数据已经在本地。RTSP 摄像机面对的是:网络抖动 丢包 乱序 服务器中断 编码器重排序 长期运行后的重连因此 RTSP 不是“把 filesrc 换成 rtspsrc”这么简单。一、先看协议层次典型 H.264 摄像机:图:RTSP/RTP 接收链:会话、抖动缓冲、Depay、Parser 与 Decoder二、先用 gst-launch 验证gst-launch-1.0-v rtspsrc location="rtsp://user:pass@host/path"latency=200 protocols=tcp `!rtph264depay!h264parse!decodebin!videoconvert!autovideosink如果摄像机是 H.265:rtph265depay ! h265parse不要凭摄像机宣传页猜。先查看-v输出、SDP 和 Dynamic Pad Caps。三、TCP 还是 UDP?UDP → 时延通常更低,不重传,网络差时可能花屏或丢帧 TCP → 可靠有序,但重传和队头阻塞可能增加延迟没有永远正确的选择。稳定局域网低延迟 → 可以测试 UDP 复杂网络、穿防火墙、完整性优先 → 常先测试 TCP四、latency 不是“端到端延迟开关”rtspsrc latency=200主要影响接收端为网络抖动准备的缓冲量,单位是毫秒。端到端延迟还来自:摄像机编码缓存 GOP / B-frame 网络 jitterbuffer Parser / Decoder queue Sink 同步把 latency 从 200 改到 0,不代表整体就变成 0 ms;反而可能让抖动更明显。五、低延迟调优顺序建议按层排查:1. 先测摄像机自身编码延迟 2. 确认 TCP / UDP 行为 3. 调整 rtspsrc latency 4. 检查 queue 是否积压 5. 检查 Decoder 是否重排序或拥塞 6. 最后决定 Sink 是否保持 syncsync=false会让 Sink 尽快呈现 Buffer,但也等于放弃正常 Clock 调度。它适合某些监控预览,不适合作为所有播放问题的默认修复。六、实时系统为什么常丢旧帧?假设解码能力只有 20 FPS,输入是 30 FPS。如果一帧不丢:积压越来越多 → 画面越来越旧监控预览常希望:丢掉已经过时的旧帧 → 尽量接近当前画面但录像分支不能照搬,因为录像需要完整数据。典型:┌→ queue(leaky) → display RTSP → depay → tee ─┤ └→ queue(non-leaky) → mux → file七、断线不是普通 EOS网络故障通常会产生 ERROR 或超时,不一定是正常 EOS。可靠重连流程:收到 ERROR ↓ 把旧 Pipeline 设为 NULL ↓ 移除回调并释放引用 ↓ 等待带上限的退避时间 ↓ 重新创建 Pipeline不要在 Bus callback 里同步销毁所有对象并立刻重连。更安全的方式是把“需要重连”投递给应用控制线程。八、凭据安全命令行中的:rtsp://user:password@host/...可能出现在:Shell 历史 进程列表 日志 错误截图生产程序应使用合适的认证 Property 或安全配置来源,并在日志中脱敏。九、RTSP 诊断清单能否连接 TCP 端口? 认证是否成功? SDP 声明什么编码? rtspsrc 新 Pad 的 Caps 是什么? Depayloader 是否匹配? Decoder 是否存在? queue current-level-time 是否增长? 错误是超时、401、not-linked 还是 not-negotiated?十、本课必须记住RTSP 管会话,RTP 承载媒体。Depayloader、Parser、Decoder 是不同层。latency 是稳定与实时的权衡,不是越小越好。sync=false会改变同步语义。预览可以丢旧帧,录像通常不能。重连应由应用控制线程管理完整 Pipeline 生命周期。十一、一个完整的 C++ 会话与有限重连控制器下面先用gst_parse_launch()让解析器处理rtspsrc的动态连接,把重点放在 Session 生命周期和重连。生产应用还应加入显式停止令牌、凭据安全存储和更细的错误分类。#includegst/gst.h#includealgorithm#includechrono#includethreadstaticboolrun_session(constchar*url){GError*parse_error=nullptr;GstElement*pipeline=gst_parse_launch("rtspsrc name=source protocols=tcp latency=200 ""! rtph264depay ! h264parse ! decodebin ""! videoconvert ! autovideosink",parse_error);if(!pipeline||parse_error){g_printerr("Parse failed: %s\n",parse_error?parse_error-message:"unknown error");g_clear_error(parse_error);if(pipeline)gst_object_unref(pipeline);returnfalse;}GstElement