
简介RTSP客户端源码包基于C语言实现面向需要学习RTSP协议或开发流媒体客户端的工程师可帮助理解客户端如何与服务器交互、控制实时流的播放、暂停与停止。代码涵盖了RTSP会话与会话ID管理、OPTIONS/DESCRIBE/SETUP/PLAY等核心方法、SDP信息解析以及RTP/RTCP传输配合机制并附Makefile提供简洁构建方式便于快速验证和二次开发。压缩包共7个文件包括3个C源文件、3个头文件和1个构建脚本整体仅19KB结构精简头文件声明接口与数据结构C文件实现具体控制逻辑Makefile负责自动化编译适合有C语言基础、希望深入网络流媒体协议栈的开发者阅读。目前已有919人学习对于想要掌握RTSP客户端设计思路的工程师可以对照源码研究连接初始化、控制请求与状态码处理、网络中断恢复策略及基于SSL/TLS的安全传输细节是一份轻量但能覆盖主要RTSP交互环节的实用样本。1. RTSPClient是什么一坨能跑的拉流代码为什么值得自己造RTSPClient是live555里专门负责拉流的C类几乎所有用RTSP协议取流的开源方案底层都绕不过它。监控项目里常见的海康摄像头取流、小米摄像头取流控制面走的都是同一套协议客户端发OPTIONS/DESCRIBE/SETUP/PLAY四步握手服务器把H264/H265码流通过RTP包推回来RTSPClient就是把这四步握手和RTP接收封装好的现成实现。它解决的实际问题很直接后端要接YOLO做目标检测、App要缓存录像、网页要转HLS在这些下游动作之前你得先有一个稳定拉流的客户端。这篇笔记会把live555编译、rtsp测试流验证、摄像头主码流子码流选择以及断流花屏的排错顺序一次讲完。适合刚接触流媒体拉流、被摄像头私有SDK折腾过的开发者。2. 先搞懂rtsp拉流协议四步握手后RTSPClient帮你接管了什么2.1 RTSP协议的四步握手OPTIONS/DESCRIBE/SETUP/PLAYRTSP控制报文走TCP默认端口554报文格式和HTTP很像请求行、若干头字段、空行、可选消息体。一次完整的播放会话固定是四步少一步设备就直接给你4xx。第一步OPTIONS客户端问服务器支持哪些方法第二步DESCRIBE带Accept头要SDP描述SDP里写着流有几路、什么编码、RTP负载类型和端口号第三步SETUP是真正的协商环节客户端要告诉服务器自己从哪个端口收RTP包服务器返回一个Session ID第四步PLAY一发RTP流就开始往客户端推了。底层的RTCP负责汇报收包统计和维持会话心跳这部分默认被很多人忽略。用openRTSP加-V参数能直接看到这四步的原始报文C-S: OPTIONS rtsp://192.168.1.64:554/Streaming/Channels/101 RTSP/1.0 C-S: CSeq: 2 C-S: User-Agent: Lavf58.76.100 S-C: RTSP/1.0 200 OK S-C: CSeq: 2 S-C: Public: OPTIONS, DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE, GET_PARAMETER, SET_PARAMETER注意请求里有个CSeq字段它是序号每发一条请求都要递增服务器响应里原样带回客户端要对得上。自己拼socket写拉流工具时最容易漏的就是CSeq和Session这两个头——漏了或者对不上海康这类设备直接回500而且响应里不会告诉你到底是哪一个字段出错排查起来全靠抓包比对。2.2 为什么自己拼socket容易翻车RTSPClient把黑匣子打开了自己写RTSP握手最脏的三件事我列一下你照着做一遍就知道为什么我不推荐从零搞。第一是摘要认证。现代摄像头默认开Digest认证不是Basic那种直接base64而是服务器先发一个nonce客户端用MD5把用户名、密码、nonce、URI拼起来做哈希。拼错一个字段就是401帧率一波动nonce还会换你得跟着重算。第二是RTP端口协商。SDP里视频和音频各占一个m行SETUP阶段每个subsession会分别协商端口用UDP拉流时端口选不好很多摄像头直接把包丢到错误端口。第三是RTCP心跳。播放期间客户端要周期性回RTCP RR报文不回的情况下一部分NVR会在拉流几分钟后静默断开连接外表看就是断流但没有任何报错。这三件事RTSPClient正好都替你处理了。live555的RTSPClient把四步握手实现成了内部状态机SDP解析交给自带库RTP接收排序交给MediaSession和MediaSink你真正需要写的只有帧到达后的回调。我见过有人不引入live555、用libcurl自己拼RTSP两星期后回来改问了下就是栽在摘要认证和RTCP心跳上。2.3 RTSPClient和RTMP/HTTP-FLV的边界拉流协议不能一套吃遍天同样做流媒体直播场景大量用RTMP而不是RTSP原因在传输层。RTSP的媒体数据用RTP承载RTP是实时传输协议只保证次序不保证可靠丢包了就丢画面表现为花屏或卡帧。监控行业接受这个因为摄像头要的是低延迟持续观看而不是每一帧都必须完美。RTMP走TCP丢包重传延迟通常在1到3秒适合直播推流但不适合监控。这里有一个选型经验下游如果是AI分析比如把监控视频拉流rtsp yolo做目标检测RTSP的低延迟就非常友好下游如果是网页播放RTSPClient拉下来的流多半还要再封装成HTTP-FLV或HLS层级一多延迟就上来了。所以动手前先想清楚终点是显示器、算法还是浏览器再决定协议栈能省掉后面一大半的折腾。3. 上手跑通rtsp测试流编译live555与最小拉流命令3.1 编译RTSPClient依赖的live555五分钟拿到openRTSPlive555是RTSPClient的宿主库它自带一个叫openRTSP的命令行客户端本质上就是对RTSPClient类的完整封装。先把它编译出来后面写自己的客户端时可以直接对照它的行为。# 去 live555.com 的 Download 页拿最新源码包解压后进入目录 tar -xzf live555-latest.tar.gz cd live # 生成 Makefile 并编译linux 环境用 Generic 配置基本不会出错 ./genMakefiles linux make -j$(nproc)编译时间通常在一两分钟以内。产物里有几个可执行文件openRTSP在testProgs目录下。这里说明两个参数genMakefiles后面的platform参数决定编译器还是交叉编译器纯Linux桌面用linuxmake的-j参数是并行核心数不要大于CPU物理核心数否则内存小一点的机器会卡死。如果编译过程中报“cannot find -lstdc”说明没装g基础包Ubuntu上执行apt install build-essential就能解决。编译完成后不要急着跑公网测试流建议先在本机用gstreamer拉一路无障碍源。gstreamer自带rtsp服务器示例一条命令就能起一个本地流# 用 gstreamer 在 8554 端口起一路测试视频 ./test-launch ( videotestsrc ! x264enc ! rtph264pay namepay0 pt96 )终端会打印rtsp://127.0.0.1:8554/test这就是你的本地rtsp测试流。用本地gstreamer服务器验证客户端逻辑比依赖公网流稳定得多也不会把生产摄像头的带宽占掉。3.2 连接rtsp测试流openRTSP参数逐项说明先拿openRTSP连本地流验证编译产物可用# -t 表示走 TCP 传输-d 5 表示只收 5 秒输出重定向到文件 ./testProgs/openRTSP -t -d 5 rtsp://127.0.0.1:8554/test test.h264这里的三个参数在生产环境几乎天天用到。-t强制RTP over RTSP把RTP数据并到TCP的RTSP连接里传解决跨网NAT下UDP收不到包的问题代价是延迟略高-d 5限制接收时长做连通性测试时防止进程一直不退重定向把H264裸流落盘。如果服务器是UDP优先不加-t时openRTSP会自动选UDP你可以对比两种方式下的丢包率和延迟差异。命令跑完没有任何报错并且test.h264文件有大小说明拉流链路通了。用ffprobe确认一下流的真实参数ffprobe test.h264输出里能看到H.264、yuv420p、分辨率、帧率这些关键信息。这一步的意义在于确认SDP解析结果如果文件里只有几十KB且ffprobe报“buffer underflow”多半是接收时丢帧严重这时要把-t以外的UDP缓冲参数调大再看。3.3 读SDPH264 profile和分辨率的出处openRTSP加-V参数会在stderr打详细信息其中有一段是DESCRIBE响应里的SDP长得像这样v0 o- 1682977332 1 IN IP4 127.0.0.1 sSession streamed by liveMedia mvideo 0 RTP/AVP 96 cIN IP4 0.0.0.0 acontrol:track1 artpmap:96 H264/90000 afmtp:96 packetization-mode1重点是mvideo这一行后面跟着的0表示端口尚未协商RTP/AVP告诉客户端用RTP承载96是负载类型编号artpmap:96 H264/90000说明负载类型96对应H264编码90000是RTP时间戳采样率afmtp里如果出现sprop-parameter-sets说明SPS/PPS直接写在了SDP里后面收帧要用它初始化解码器packetization-mode1则指H264按非交错模式打包每个RTP包一个NALU为主。这些值不是给你看的。写RTSPClient的帧处理逻辑时需要从SDP解析出编码类型、负载类型、时间戳频率然后才能正确地把RTP负载还原成NAL单元。live555的MediaSession::initWithSDP会把这些字段解析到MediaSubsession里你直接用subsession-rtpPayloadFormat()和subsession-videoWidth()这类接口就能拿到。很多新手在这步手写SDP解析一个漏了分号就可能把整个会话带偏用库的解析接口会省心很多。4. 接摄像头实战海康rtsp取流地址与主码流子码流怎么选4.1 海康和大华摄像头rtsp取流地址的拼法不同品牌的取流地址格式不同但核心结构都一样协议头加认证信息加设备ip后面跟流通道路径。海康最典型主码流和子码流用数字通道区分品牌取流地址格式说明海康rtsp://用户名:密码IP:554/Streaming/Channels/101101主码流102子码流海康rtsp://用户名:密码IP:554/Streaming/Channels/201201第二通道主码流大华rtsp://用户名:密码IP:554/cam/realmonitor?channel1subtype0subtype0主码流1子码流小米rtsp://用户名:密码IP:554/stream1需在客户端开启RTSP功能海康、大华的地址在官方文档和工程资料里都能查到小米摄像头不是所有固件都有RTSP功能开了以后地址格式各版本有差异建议去路由器后台看设备ip再结合App里的固件说明确认。这里要提醒两点第一URL里的用户名密码建议用urlencode编码密码里只要出现、?、这类字符不编码的话地址解析就会错乱第二很多摄像头默认不开RTSP需要先在Web管理页面把“启用RTSP”打开否则端口探测是通的DESCRIBE却一直超时。4.2 主码流和子码流分辨率、码率、延迟怎么权衡主码流是摄像头的主输出分辨率高、码率高目的是给本地录像或大屏显示提供高质量画面。子码流是次输出分辨率低、码率低主要给手机预览、多路轮巡这类低带宽场景。工程上最常见的错误是无论什么需求都拉主码流结果一个200万像素的H264主码流动辄4到8Mbps十个摄像头同时拉就占满了交换机带宽。拉流前先问自己要干什么。如果下游是YOLO检测目标框只需要能分辨人车级别子码流720P一般就够码率只有主码流的四分之一GPU解码开销也小得多。如果下游要人脸识别子码流画面细节不足必须用主码流。如果你既要检测又要预览标准做法是同一路摄像头同时拉两路一路主码流给录像一路子码流给检测而不是反复切换同一路会话。因为RTSP是时分复用协议同一路播放会话不能同时给两个消费者多进程各拉各的流才是工程常态。4.3 把RTSPClient的帧喂给YOLO常见桥接方案live555的RTSPClient回调拿到的不是YUV或RGB帧而是H264/H265的NAL单元必须经过解码才能给YOLO用。最常见的落地架构是三层RTSPClient拉流、ffmpeg或硬件解码器解出YUV、检测线程推理。帧到达回调一般长这样// DummySink::afterGettingFrame 是 RTSPClient 每收到一帧的入口 void afterGettingFrame(unsigned frameSize, unsigned numTruncatedBytes, struct timeval presentationTime, unsigned durationInMicroseconds) { // fReceiveBuffer 里是一个完整的 NALU先把帧序号和时间戳记下来 naluSeq rtpInfo-seqNum; timestamp presentationTime; // 交给解码器解出 YUV再转 RGB 送进环形队列给检测线程消费 int w decoder-decode(fReceiveBuffer, frameSize, yuvBuffer); frameQueue.push(yuvBuffer, w); }回调里不能做同步推理否则RTSPClient收包的循环会被卡住UDP缓冲区一满就开始丢RTP包。常见做法是回调里只解析NALU并丢进一个有界环形队列YOLO检测线程从队列里取帧做前处理、推理、后处理。队列深度建议控制在5到10帧太浅会丢关键帧导致检测漏报太深则画面延迟直线上升。做完检测还要把结果叠加回画面时注意RTSP拉流的帧时间戳不能直接当系统时间用摄像头的时间戳是基于开机时间的要换算成unix时间再做同步。这里我吃过亏直接把RTP时间和系统时钟对齐结果画面时间戳比实际时间慢了一个多小时排查了半天发现是时区转换没做。5. RTSPClient避坑指南断流、花屏和OOM的排查顺序5.1 现象握手上去了但一直收不到帧现象openRTSP或自己的客户端已经发出PLAY并收到200 OK但afterGettingFrame一直不被调用网络抓包能看到服务器在推RTP包就是到不了应用层。原因最常见的是SETUP阶段传输方式协商失败。live555默认尝试UDP传输但在NAT后面或者防火墙只放开TCP 554端口的场景UDP回包根本到不了客户端。服务器视角是PKT已经发出客户端视角是包永远没来。另一种情况是RTSPClient的CSeq在摘要认证重试后被重置导致服务器认为序列号乱序丢弃PLAY请求。解决优先强制走TCP隧道即RTP over RTSP。openRTSP加-t自定义客户端则要在SETUP阶段把RTP端口设为0让服务器把RTP数据并到RTSP的TCP连接里用interleaved0-1发送。这样单端口就能拉流NAT和防火墙问题一起解决代价是延迟比UDP模式高约20到50毫秒一般场景可以接受。5.2 现象画面花屏和块状马赛克现象画面能出来但不断出现大块色块特别是画面剧烈变化时更明显偶尔还会卡在上一个关键帧的残影上。原因RTP包在传输中丢失。UDP模式下丢包率高是常态带宽不足、交换机缓冲小、Wi-Fi干扰都可能触发。丢包后解码器拿残破的P帧硬解产生马赛克如果丢的是关键帧画面直接碎到下一个关键帧到来前都缓不过来。解决第一选择还是切TCP拉流TCP不会丢包只会推高延迟。如果必须用UDP比如对延迟极其敏感的场合要在RTSPClient的RTP接收侧检测序列号跳跃RTP头里的sequence number每包加一如果发现下一包序号跳了说明丢包了正确的策略是丢弃整个GOP等下一个关键帧再恢复解码而不是把缺块的P帧送进去解码。5.3 现象内存暴涨和延迟越拉越大现象程序刚启动时画面秒开跑10分钟后延迟累加到几秒同时内存占用直线上升最后被系统杀掉。这在安卓端缓存rtsp流的场景特别常见。原因把RTSPClient收到的每一帧都先塞进无界队列消费端解码或推理速度跟不上RTP到达速度队列越积越长。这是典型的“生产大于消费”问题网络输入速率是摄像头决定的消费速率是CPU/GPU决定的二者不匹配时无界缓冲就是内存炸弹。解决给缓冲加上限满了就丢最旧的帧保新鲜度而不是保完整。简单实现就是在回调里检查队列长度超过阈值直接pop掉最早一帧再push新帧。这个策略对检测场景尤其重要检测看的是“现在”的画面迟到的帧没有任何价值只会让延迟滚雪球。5.4 现象断网后重连失败只能重启App现象Wi-Fi断开又恢复后程序的RTSPClient一直卡在“连接中”状态超时、重试、再超时循环几轮后彻底没反应只能杀掉进程重启。原因断网的瞬间RTSPClient所在的socket停在CLOSE_WAIT或TIME_WAIT如果重连前没有释放旧的RTSPClient实例和它的RTP会话内核里的文件描述符会一直累积。连续重试几次后fd耗尽新连接连socket都创建不出来。解决重连前先做完整的teardown。先调teardownMediaSession发送TEARDOWN报文再删除MediaSession和RTSPClient实例设置socket为SO_REUSEADDR最后等待1到2秒让内核清理TIME_WAIT再发起下一次连接。如果设备地址变了DHCP重分配重连前还要重新解析IP直接用旧IP连必然超时。6. 进阶RTSPClient抗造调优的最后三招6.1 指数退避重连直接写死固定间隔重连不靠谱5秒一次断网10分钟就得重试120次日志刷屏服务器还可能把频繁连接的IP封掉。我的习惯是初始1秒、每次翻倍、上限30秒加一点随机抖动防抖int delay 1; while (!connected) { if (tryConnect()) break; sleep(delay random(0, 3)); delay min(delay * 2, 30); }关键不是算法而是重连成功后要把delay重置为1不然每次断流都要等30秒恢复人早就骂了。6.2 缓冲水位与丢帧策略很多人在“卡顿”和“延迟”之间作低价取舍其实可以两个都要。给帧队列设高低水位低于低水位正常入队高于高水位时丢弃非关键帧只保I帧但水位的判定要基于解码时间而不是队列帧数。6.3 倍速回放与最后的验证习惯RTSP的PLAY请求可以用Scale头控制播放速度海康NVR回放时快进4倍拿到的就是这个机制。RTSPClient发PLAY时带上Scale: 4.0服务器会按四倍速度推流但不同设备对倍速支持的区间不同超范围会直接拒播。验证客户端稳定性的最实用习惯不是看日志而是抓包统计RTP序号连续率连续一小时丢包率低于0.1%且无断流这个客户端才算真正抗造。这一路写下来我最大的教训是RTSPClient本身很稳出问题的地方几乎都在上游网络和下游消费。先抓包再调参数别一上来就改代码。希望帮到你。本文还有配套的精品资源点击获取