认识流媒体协议,从RTSP协议解析开始
RTSP是Internet协议规范,是TCPIP协议体系中的一个应用层协议级网络通信系统。专为娱乐(如音频和视频)和通信系统的使用,以控制流媒体服务器。该协议用于在端点之间建立和控制媒体会话。媒体服务器的客户端发出VHS样式的命令,例如:PLAY、PAUSE、SETUP、DESCRIBE、RECORD等等。以促进对从服务器到客户端或从客户端到服务器的媒体流进行实时控制。
RTSP传输过程当用户或应用程序尝试从远程源流式传输视频时,客户端设备会向服务器发送RTSP请求,以确定可用选项,例如PLAY,PAUSE、SETUP然后,服务器返回它可以通过RTSP接受的请求类型的列表。客户端知道如何发出请求后,便将媒体描述请求发送到流服务器。服务器以媒体描述作为响应。客户端从那里发送设置请求,服务器以有关传输机制的信息作为响应。设置过程完成后,客户端将通过告诉服务器使用设置请求中指定的传输机制发送位流(二进制序列)来启动流传输过程。客户端服务器:DESCRIBE
服务器客户端:200OK(SDP)
客户端服务器:SETUP
服务器客户端:200OK
客户端服务器:PAUSE
。。。
协议的分析和学习少不了抓包,截屏个RTSP协议抓包的图:
为什么RTS协议那么重要RTSP最初是一种允许用户直接从Internet播放音频和视频,而不必将媒体文件下载到其设备的方法。该协议已被应用于多种用途,包括互联网摄像机站点,在线教育和互联网广播。RTSP使用与基本HTTP相同的概念,在很大程度上是为了兼容现有的Web基础结构。正因如此,HTTP的扩展机制大都可以直接引入到RTSP中。RTSP协议还具有很大的灵活性。客户端可以请求他们要使用的功能,以找出媒体服务器是否支持它们。同样,拥有媒体的任何人都可以从多个服务器传递媒体流。该协议还旨在适应媒体的未来发展,以便媒体创建者可以在必要时修改协议。
RTSP协议指令
尽管RTSP在某些方面类似于HTTP,但它定义了可用于控制多媒体播放的控制序列。尽管HTTP是无状态的,但RTSP却具有状态。
在需要跟踪并发会话时使用标识符。像HTTP一样,RTSP使用TCP来维护端到端连接,端口号为554。
尽管大多数RTSP控制消息是由客户端发送到服务器的,但是某些命令却是朝着另一个方向(即从服务器到客户端)传递的。
下面我们来介绍基本的RTSP请求:
SETUP
SETUP请求指定必须如何传输单个媒体流。必须在发送PLAY请求之前完成此操作。
该请求包含媒体流URL和传输说明符。
该说明符通常包括一个本地端口,用于接收RTP数据(音频或视频),另一个用于RTCP数据(元信息)。
服务器答复通常会确认选定的参数,并填写缺少的部分,例如服务器的选定端口。必须先使用SETUP配置每个媒体流,然后才能发送聚合播放请求。
PLAY
PLAY请求将导致播放一个或所有媒体流。可以通过发送多个PLAY请求来堆叠播放请求。该URL可以是聚合URL(以播放所有媒体流),也可以是单个媒体流URL(仅播放该流)。
可以指定范围。如果未指定范围,则从头开始播放并播放到结尾,或者,如果流已暂停,则在暂停点恢复播放。
PAUSE
PAUSE请求会暂时中止一个或所有媒体流,因此稍后可以通过PLAY请求将其恢复。该请求包含聚合或媒体流URL。
PAUSE请求上的range参数指定何时暂停。如果省略range参数,则暂停将立即无限期地发生。
RECORD
此方法根据演示说明开始记录一系列媒体数据。时间戳反映开始时间和结束时间(UTC)。如果没有给出时间范围,请使用演示说明中提供的开始时间或结束时间。
如果会话已经开始,请立即开始录制。服务器决定是否将记录的数据存储在请求URl或其他URI下。
如果服务器未使用请求URI,则响应应为201,并包含描述请求状态并引用新资源的实体和位置标头。
【腾讯文档】FFmpegWebRTCRTMPRTSPHLSRTP播放器音视频流媒体高级开发资料领取FFmpegWebRTCRTMPRTSPHLSRTP鎾斁鍣闊宠棰戞祦濯掍綋楂樼骇寮鍙璧勬枡棰嗗彇
ANNOUNCE
当从客户端发送到服务器时,ANNOUNCE将请求URL标识的演示或媒体对象的描述发布到服务器。ANNOUNCE会实时更新会话描述。
如果将新的媒体流添加到演示文稿中(例如,在现场演示文稿中),则应再次发送整个演示文稿说明,而不仅仅是其他组件,以便可以删除这些组件。
TEARDOWN
TEARDOWN请求用于终止会话。它停止所有媒体流并释放服务器上所有与会话相关的数据。
GETPARAMETER
GETPARAMETER请求检索URI中指定的表示形式或流的参数值。答复和响应的内容留给实现。
SETPARAMETER
此方法要求为URI指定的表示或流设置参数值。
WiresharkRTSP协议解析实现
对RTSP协议的使用有了一个大概的了解之后,我们来解析实现一下RTSP协议。includesysstat。hincludesystypes。hincludenetinettcp。hincludenetinetudp。hincludenetinetip。hincludenetinetip6。hincludenetethernet。hincludepcap。hincludestdio。hincludestdlib。hincludestring。hincludectype。hRTSP端口defineRTSPTCPPORTRANGE554typedefenum{RTSPREQUEST,RTSPREPLY,RTSPNOTFIRSTLINE}rtsptypet;staticconstcharrtspmethods〔〕{DESCRIBE,ANNOUNCE,GETPARAMETER,OPTIONS,PAUSE,PLAY,RECORD,REDIRECT,SETUP,SETPARAMETER,TEARDOWN};用于RTSP统计structrtspinfovaluet{charrequestmethod;unsignedlongintresponsecode;};假定一个字节数组(假定包含一个以空值结尾的字符串)作为参数,并返回字符串的长度即该数组的大小,对于空终止符的值减去1。defineSTRLENCONST(str)(sizeof(str)1)staticconstcharrtspcontenttype〔〕ContentType:;staticconstcharrtsptransport〔〕Transport:;staticconstcharrtspspsserverport〔〕serverport;staticconstcharrtspcpsserverport〔〕clientport;staticconstcharrtspspsdestaddr〔〕destaddr;staticconstcharrtspcpssrcaddr〔〕srcaddr;staticconstcharrtsprtpudpdefault〔〕rtpavp;staticconstcharrtsprtpudp〔〕rtpavpudp;staticconstcharrtsprtptcp〔〕rtpavptcp;staticconstcharrtsprdtfeaturelevel〔〕RDTFeatureLevel;staticconstcharrtsprealrdt〔〕xrealrdt;staticconstcharrtsprealtng〔〕xpntng;synonymforxrealrdtstaticconstcharrtspinter〔〕interleaved;staticconstcharrtspcontentlength〔〕ContentLength:;staticvoidrtspcreateconversation(ucharlinebegin,sizetlinelen,rtsptypetrtsptypepacket){charbuf〔256〕;chartmp;boolrtpudptransportfalse;boolrtptcptransportfalse;boolrdttransportfalse;boolisvideofalse;是否需要显示视频unsignedintcdataport,cmonport;unsignedintsdataport,smonport;unsignedintipv41,ipv42,ipv43,ipv44;if(rtsptypepacket!RTSPREPLY){return;}将行复制到bufif(linelensizeof(buf)1){避免溢出缓冲区。linelensizeof(buf)1;}memcpy(buf,linebegin,linelen);buf〔linelen〕;printf(s,buf);GetpastTransport:andspacestmpbufSTRLENCONST(rtsptransport);printf(tmps,tmp);while(tmpisspace(tmp))tmp;if((tmpstrstr(buf,rtspcpssrcaddr))){tmpstrlen(rtspcpssrcaddr);printf(tmps,tmp);if(sscanf(tmp,u。u。u。u:u,ipv41,ipv42,ipv43,ipv44,cdataport)5){chartmp2;chartmp3;printf(ipv41d,ipv41);printf(ipv42d,ipv42);printf(ipv43d,ipv43);printf(ipv44d,ipv44);printf(cdataportd,cdataport);Skipleadingtmp;tmp2strstr(tmp,:);tmp3strndup(tmp,tmp2tmp);printf(srcaddrs,tmp3);free(tmp3);}}if((tmpstrstr(buf,rtspspsdestaddr))){tmpstrlen(rtspspsdestaddr);if(sscanf(tmp,:u,sdataport)1){:9meanignoreif(sdataport9){sdataport0;}printf(sdataportd,sdataport);}}if((tmpstrstr(buf,rtspspsserverport))){tmpstrlen(rtspspsserverport);if(sscanf(tmp,u,smonport)1){printf(smonportd,smonport);}}}staticboolisrtsprequestorreply(unsignedcharline,intoffset,rtsptypettype){unsignedintii0;chardatareinterpretcastchar(line);inttokenlen;charresponsechars〔4〕;structrtspinfovaluetrtspinfo;chartoken,nexttoken;这是RTSP的回复?if(strncasecmp(RTSP,data,5)0){Yes。typeRTSPREPLY;第一个标记是版本。offset9;memcpy(responsechars,dataoffset,3);responsechars〔3〕;rtspinfo。responsecodestrtoul(responsechars,NULL,10);printf(rtspinfo。responsecoded,rtspinfo。responsecode);returntrue;}这是RTSP请求吗?检查该行是否以RTSP请求方法之一开头。for(ii0;iisizeofrtspmethodssizeofrtspmethods〔0〕;ii){sizetlenstrlen(rtspmethods〔ii〕);if(strncasecmp(rtspmethods〔ii〕,data,len)0(isspace(data〔len〕))){typeRTSPREQUEST;rtspinfo。requestmethodstrndupa(rtspmethods〔ii〕,len1);printf(requestmethod:s,rtspinfo。requestmethod);returntrue;}}既不是请求也不是回应typeRTSPNOTFIRSTLINE;returnfalse;}阅读回复消息的第一行staticvoidprocessrtspreply(ucharrtspdata,intoffset,rtsptypetrtsptypepacket){charlineendreinterpretcastchar(rtspdataoffset);charstatusreinterpretcastchar(rtspdata);charstatusstart;unsignedintstatusi;statuscodeSkipprotocolversionwhile(statuslineend!isspace(status))status;Skipspaceswhile(statuslineendisspace(status))status;Actualcodenumbernowstatusstartstatus;printf(statusstarts,statusstart);statusi0;while(statuslineendisdigit(status))statusistatusi10status0;printf(statusid,statusi);offsetstrlen(lineend);rtspcreateconversation(rtspdata,offset,rtsptypepacket);}staticvoidprocessrtsprequest(ucharrtspdata,intoffset,rtsptypetrtsptypepacket){charlineendreinterpretcastchar(rtspdataoffset);ucharlineendrtspdataoffset;unsignedintii0;charurl;charurlstart;charbuf〔256〕;chartmp;intcontentlength0;charcontenttype〔256〕;RequestMethodsfor(ii0;iisizeofrtspmethodssizeofrtspmethods〔0〕;ii){sizetlenstrlen(rtspmethods〔ii〕);if(strncasecmp(rtspmethods〔ii〕,lineend,len)0(isspace(lineend〔len〕)))break;}printf(processrtsprequest0x。2X,0x。2X,0x。2X,0x。2X,lineend〔0〕,lineend〔1〕,lineend〔2〕,lineend〔3〕);URLurllineend;Skipmethodnameagainwhile(urllineend!isspace(url))url;Skipspaceswhile(urllineendisspace(url))url;URLstartshereurlstarturl;ScantoendofURLwhile(urllineend!isspace(url))url;printf(s,urlstart);printf(111urls,url);if((tmpstrstr(urlstart,rtspcontenttype))){tmpstrlen(rtspcontenttype);if(sscanf(tmp,s,contenttype)1){printf(contenttypes,contenttype);}}ContentLengthif((tmpstrstr(urlstart,rtspcontentlength))){tmpstrlen(rtspcontentlength);if(sscanf(tmp,u,contentlength)1){printf(contentlengthd,contentlength);}}}voiddissectrtsp(ucharrtspdata){intoffset0;rtsptypetrtsptypepacket;boolisrequestorreply;ucharlinep,lineend;ucharc;boolisheaderfalse;isrequestorreplyisrtsprequestorreply(rtspdata,offset,rtsptypepacket);if(isrequestorreply)gotoisrtsp;isrtsp:switch(rtsptypepacket){caseRTSPREQUEST:processrtsprequest(rtspdata,offset,rtsptypepacket);break;caseRTSPREPLY:processrtspreply(rtspdata,offset,rtsptypepacket);break;caseRTSPNOTFIRSTLINE:Dropthrough,itmaywellbeaheaderlinebreak;default:break;}}staticvoiddissectrtsptcp(structippIp){intiHeadLenpIpiphl4;intiPacketLenntohs(pIpiplen)iHeadLen;intoffset0;intnFragSeq0;structtcphdrpTcpHdr(structtcphdr)(((char)pIp)iHeadLen);if(pIpippIPPROTOTCP(ntohs(pTcpHdrdest)RTSPTCPPORTRANGE)(ntohs(pTcpHdrsource)RTSPTCPPORTRANGE))仅处理TCP协议{intiPayloadLeniPacketLenpTcpHdrdoff4;printf(TCPPayloadLend,iPayloadLen);ucharRtspHdr(uchar)(pTcpHdr1);if(RtspHdrNULL)return;ucharRtspDataRtspHdr12;skipOPtionsprintf(NtpHdr0x。2X,0x。2X,0x。2X,0x。2X,RtspData〔0〕,RtspData〔1〕,RtspData〔2〕,RtspData〔3〕);dissectrtsp(RtspData);}}复制代码
编译运行
RTSP是一种基于文本的协议,用回车换行(r)作为每一行的结束符,其好处是,在使用过程中可以方便地增加自定义参数,也方便抓包分析。
从消息传送方向上来分,RTSP的报文有两类:请求报文和响应报文。请求报文是指从客户端向服务器发送的请求,响应报文是指从服务器到客户端的回应。
总结
RTSP对流媒体提供了诸如PLAY,PAUSE、SETUP等控制,但它本身并不传输数据,RTSP的作用相当于流媒体服务器的远程控制。
服务器端可以自行选择使用TCP或UDP来传送串流内容,它的语法和运作跟HTTP类似。更多解析请参考RFC官方文档,也是最权威的文档。
作者:声网链接:https:juejin。cnpost7016675635942670366来源:稀土掘金著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
魔域手游2最强法师加点攻略,小白上手零难度《魔域手游2》是最近刚刚开启了巅峰测试的一款手游,受到非常多玩家的欢迎与喜爱。作为一款MMORPG手游,它的主要玩法是让玩家进入魔幻世界,完成主线任务并不断地升级,养成自己的角……
夏天这蒸菜多做给家人吃,蒸一蒸7分钟出锅,真鲜嫩!营养不上火夏天,少吃牛羊肉多吃它,10元一斤,加料和丝瓜蒸一蒸,真鲜嫩!今天是小暑节气,小暑的到来也意味着气候开始越来越炎热了,三伏天的脚步也越来越近了,热天就特别容易让人食欲不振,吃啥……
一招教你在家制作云南过桥米线今日美食美食工坊米线米线汤底配料实用菜谱云南过桥米线用料:云南米线1把、鱼片1碟、猪里脊肉1碟、鸡胸肉1碟、蘑菇1碟、酥肉一碟、豆芽1……
市场为什么没有塑料瓶装啤酒呢?你去青岛看看,有塑料袋装的啤酒。有塑料瓶的啤酒但是极少,市场有卖俄罗斯北极熊啤酒就是塑料瓶的1。5升的绿塑料瓶先调研再提问,要不然显得水平很那啥俄罗斯啤酒基本……
邓伦因逃税登上热搜后,其家庭背景被网友扒出,网友难以理解纳税是每个公民应尽的义务,公民平时所缴纳的税主要是个人所得税,就是您打工所获得的收入是要上交给国家一部分的,一般来说你个人所获得收入越高所缴纳的费用就会越多。可能有人会认……
76人输球的原因找到了球迷朋友们期待已久的NBA揭幕战终于开打。北京时间10月19日,NBA常规赛第一场,哈登跟恩比德带领的76人队挑战双探花带领的凯尔特人队,最终76人以117:126败给绿……
吃了那么多年牛肉你了解什么是谷饲和草饲么?来源:经济日报中国经济网中国饮食文化源远流长,经过千年发展,形成了众多菜系和烹饪方式。涮牛肉、酱牛肉、红烧牛肉、炖牛肉这些牛肉吃法耳熟能详,也是国人日常菜品的常见种类。西……
这真徕卡!小米12S系列参数一览小米12S搭载新一代骁龙8芯片,由台积电4nm工艺打造。尺寸方面为152。67mm69。9mm8。16mm,重量182g。储存为LPDDR5内存UFS3。1闪存的组合。屏……
30套气质搭配,每天美的不一样眼花缭乱的世界常常让人茫然无绪。如何毫不造作地体现品位?又如何独立于滚滚烟云中,俏也不争?像有一股气息一笼细雨一身衣着便是一道帘幕,将……
请问白糖熏鸡,糖的比例是多少?我熏的发苦为什么,谢谢老师们?谢邀回答。熏是将熏料放在锅中,利用不充分燃烧时产生的烟气使食材成熟、上色、并形成特殊香气的一种烹调技法。根据熏料不同熏可分:纯糖熏,柏木熏,谷糠熏等。根据食材的生熟度,熏……
胃不好早餐吃什么养胃?胃不好早餐吃什么养胃胃不好的患者早餐可以吃些易消化的面食、粥类、汤水、牛奶等。养胃的食物有很多,主要分为以下几类。粥类。粥是养胃食物最好的选择,它非常容易消化……
喝红酒的好处是什么?喝红酒对身体有什么好处?喝红酒有促进胃酸分泌、减肥瘦身、美容养颜等好处,具体如下。1。促进胃酸分泌:红酒中含有的单宁类物质可以增加肠道平滑肌纤维收缩,调整肠道功能,……