rtsp协议格式解析

Posted breakpointlab

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了rtsp协议格式解析相关的知识,希望对你有一定的参考价值。

前言

网上关于rtsp的文章很多,但大多是抽象的理论介绍,从理论学习到实际上手开发往往还有一段距离。然而,没有实际开发经验的支撑,理论又很难理解到位。

本系列文章将从流媒体协议的基础原理开始,通过抓包分析,并结合具体的代码例程,以[原理]->[抓包]->[代码]相结合的方式,循序渐进由浅入深的介绍rtsp/rtp/rtcp开发相关的内容。

希望通过本系列内容的学习,能让大家快速入门流媒体开发需要掌握的技能。

欢迎大家关注[断点实验室]流媒体开发系列文章。
rtsp协议开发指南
rtsp协议格式解析
rtsp协议报文解析-请求行解析
rtsp协议报文解析-首部字段解析

1 RTSP与HTTP协议比较

rtsp协议在语法及一些消息参数等方面与http协议类似,这里之所以引入http的相关内容,是为了通过我们熟悉的http协议,来帮助大家快速理解rtsp协议的工作原理。

1.1 RTSP与HTTP协议的相同点

rtsp是一种基于文本的协议,在语法及消息参数等方面与http协议类似,它通过一系列格式化的文本信息,传递与实时视频流传输相关的一些控制命令及状态参数。

rtsp采用与http协议类似的报文结构,包括请求行、首部行以及实体主体三部分,因此可以通过抓包很直观的对协议内容进行分析,下图为http协议报文格式。

rtsp协议引入了大多数http1.1的状态码,来反馈当前的响应状态,客户端根据这些状态码来判断服务器状态。

static const rtsp_msg_int2str_tbl_s rtsp_msg_status_code_tbl[] = 
	100, 0, "Continue",
	200, 0, "OK",
	201, 0, "Created",
	250, 0, "Low on Storage Space",
	300, 0, "Multiple Choices",
	301, 0, "Moved Permanently",
	302, 0, "Moved Temporarily",
	303, 0, "See Other",
	305, 0, "Use Proxy",
	400, 0, "Bad Request",
	401, 0, "Unauthorized",
	402, 0, "Payment Required",
	403, 0, "Forbidden",
	404, 0, "Not Found",
	405, 0, "Method Not Allowed",
	406, 0, "Not Acceptable",
	407, 0, "Proxy Authentication Required",
	408, 0, "Request Timeout",
	410, 0, "Gone",
	411, 0, "Length Required",
	412, 0, "Precondition Failed",
	413, 0, "Request Entity Too Large",
	414, 0, "Request-URI Too Long",
	415, 0, "Unsupported Media Type",
	451, 0, "Invalid parameter",
	452, 0, "Illegal Conference Identifier",
	453, 0, "Not Enough Bandwidth",
	454, 0, "Session Not Found",
	455, 0, "Method Not Valid In This State",
	456, 0, "Header Field Not Valid",
	457, 0, "Invalid Range",
	458, 0, "Parameter Is Read-Only",
	459, 0, "Aggregate Operation Not Allowed",
	460, 0, "Only Aggregate Operation Allowed",
	461, 0, "Unsupported Transport",
	462, 0, "Destination Unreachable",
	500, 0, "Internal Server Error",
	501, 0, "Not Implemented",
	502, 0, "Bad Gateway",
	503, 0, "Service Unavailable",
	504, 0, "Gateway Timeout",
	505, 0, "RTSP Version Not Supported",
	551, 0, "Option not support",
;

1.2 RTSP与HTTP协议的不同点

http协议是无状态的协议,它的每个请求都是完全独立的,每个请求包含了处理这个请求所需的完整的数据,发送请求不涉及状态变更

例如,当浏览器第一次发送请求给服务端时,服务端响应了,如果同一浏览器向服务端再次发送相同请求时,服务端还是会执行相同的响应(当然服务端可以通过cookie记录与客户端通信的状态信息,这是另一个问题)。

与http服务端不同的是,rtsp服务端几乎在所有情况下都需要默认维护状态,这与http的无状态性质相反。

此外,rtsp与http的根本不同在于,http的数据传输(如照片等)是通过http协议本身实现的,客户端发出资源请求,服务端在响应中传递数据。在rtsp中,视频流是通过rtp协议传输的,rtsp可以设置参数并在传输结束后很长时间内继续控制媒体流。

2 RTSP协议报文格式解析

与http协议类似,rtsp协议也是面向文本的(text-oriented)协议,报文内容可以看作是由ASCII码组成字符缓存,对协议的封装与解析,就是按照协议的报文格式,组装或解析对应的字符串码

2.1 RTSP协议报文结构

rtsp报文由三部分组成,即开始行、首部行和实体主体。在请求报文中,开始行就是请求行。rtsp请求报文的结构如下图所示。


rtsp响应报文的结构如下图所示。


报文中的部分字段(如url字段等)长度是不固定的,首部行包含的首部字段个数也不是固定的,因此,协议通过空格及CRLF将各个字段内容信息分割开来,用空格作为一个字段结束的标识,用CRLF作为一行结束的标识,协议的封装解析可以以此为依据进行设计。

2.2 RTSP协议报文方法

协议报文方法包括OPTIONS,DESCRIBE,SETUP,PLAY,TEARDOWN等,具体含义如下表所示,其中C标识客户端,S标识服务器。

方向方法描述作用
C->SOPTION request询问对端有哪些可用方法OPTION用于查询服务器端可用方法
S->COPTION response回应S所有可用方法
C->SDESCRIBE request取得S媒体描述信息DESCRIBE用于取得媒体描述信息
S->CDESCRIBE response回应媒体描述信息
C->SSETUP request请求建立会话连接SETUP用于建立RTSP会话连接
S->CSETUP response建立会话连接
C->SPLAY requestC请求S开始发送数据PLAY用于请求开始发送数据
S->CPLAY responseS回应该请求的信息
C->STEARDOWN request请求关闭会话TEARDOWN用于结束RTSP会话
S->CTEARDOWN responseS回应退出请求

2.3 RTSP协议首部行

与http协议类似,rtsp协议的首部字段是构成rtsp报文的要素之一,它为客户端和服务端提供报文交互所需的报文序列号、使用的语言、报文日期等内容,如:

  • Accept字段告诉服务端,客户端在rtsp请求与响应中能够接受的数据内容或数据类型。
  • User-Agent字段告诉服务端,发起请求客户端的描述信息。

下表列出了rtsp协议使用的首部行字段,在type列中类型"g"表示在请求和响应报文中都会用到的通用字段,"R"表示请求报文字段,"r"表示响应报文字段,"e"表示实体主体字段。

support列中的"req."字段表示对应的首部行字段,在相关类型的报文中必须要包含的,而标记为"opt."的字段是可选的,如:

  • CSeq为报文序列号,所有请求/响应报文都需要包含该首部行字段。

methods列中列出的方法为各个首部行字段实际使用的报文场景,如Range字段一般应用于PLAY, PAUSE, RECORD这三个报文中,表示视频流在PLAY, PAUSE, RECORD这三个操作中的作用范围。

Headertypesupportmethods
AcceptRopt.entity
Accept-EncodingRopt.entity
Accept-LanguageRopt.all
Allowropt.all
AuthorizationRopt.all
BandwidthRopt.all
BlocksizeRopt.all but OPTIONS, TEARDOWN
Cache-Controlgopt.SETUP
ConferenceRopt.SETUP
Connectiongreq.all
Content-Baseeopt.entity
Content-Encodingereq.SET_PARAMETER
Content-Encodingereq.DESCRIBE, ANNOUNCE
Content-Languageereq.DESCRIBE, ANNOUNCE
Content-Lengthereq.SET_PARAMETER, ANNOUNCE
Content-Lengthereq.entity
Content-Locationeopt.entity
Content-Typeereq.SET_PARAMETER, ANNOUNCE
Content-Typerreq.entity
CSeqgreq.all
Dategopt.all
Expireseopt.DESCRIBE, ANNOUNCE
FromRopt.all
If-Modified-SinceRopt.DESCRIBE, SETUP
Last-Modifiedeopt.entity
Proxy-RequireRreq.all
Publicropt.all
RangeRopt.PLAY, PAUSE, RECORD
Rangeropt.PLAY, PAUSE, RECORD
RefererRopt.all
RequireRreq.all
Retry-Afterropt.all
RTP-Inforreq.PLAY
ScaleRropt.PLAY, RECORD
SessionRrreq.all but SETUP, OPTIONS
Serverropt.all
SpeedRropt.PLAY
TransportRrreq.SETUP
Unsupportedrreq.all
User-AgentRopt.all
Viagopt.all
WWW-Authenticateropt.all

以上内容对报文首部行字段做了简要的介绍,限于篇幅的原因无法对每个字段进行深入的介绍,感兴趣的读者可以参考rtsp协议规范RFC2326中[12. Header Field Definitions]中的相关内容,也可直接参考http协议中关于这部分内容的相关描述,网上应该很容易找到,后续文章会对代码中涉及的相关信息再做进一步的解读。

3、RTSP协议会话流程抓包分析

协议的基本原理讲完了,下面带大家分析协议的交互过程及抓包分析。

3.1 RTSP协议会话流程

一个基本的rtsp会话流程,包括客户端向服务端请求支持的操作类型,发送建立会话请求,请求发送流媒体数据等,会话流程如下图所示。


下面的抓包截图反映了客户端与服务端的实际交互过程。

3.2 RTSP协议抓包分析

  • 向服务端请求媒体描述信息

C->S:DESCRIBE request //请求S提供的媒体描述信息

S->C:DESCRIBE response //S回应媒体描述信息,一般是sdp格式信息

  • 建立RTSP会话

C->S:SETUPrequest //通过Transport头字段列出可接受的传输选项,请求S建立会话

S->C:SETUPresponse //S建立会话,通过Transport头字段返回选择的具体转输选项,并返回建立的Session ID

  • 请求开始传送数据

C->S:PLAY request //C请求S开始发送数据

S->C:PLAYresponse //S回应该请求的信息

  • 视频推流

S->C:发送流媒体数据 //通过RTP协议传送数据

4、RTSP协议代码实现

前面内容介绍了协议的基础原理及抓包分析,下面我们来结合代码继续讲解。

这里我们以流媒体开发系列文章rtsp协议入门指南中引入的推流端代码为例,讲述rtsp协议报文的解析及封装过程。

4.1 RTSP协议数据结构

推流端代码按照rtsp协议报文格式,设计一个存储协议各格式化信息的数据结构,数据结构中的各个结构分别描述了格式化报文信息中的相应内容。

报文的解析及组装过程,可以看作在依照协议文本格式及语法规则的情况下,在报文文本信息与协议数据结构之间相互转换,即

  • 报文解析:从网络接口读报文信息到缓存,将缓存中的文本信息按照不同报文格式提取出来,存储到协议数据结构中,即字符串码->协议数据结构

  • 报文组装:创建报文缓存,根据服务端当前的状态将待发送的报文内容存储到协议数据结构中,最后将协议数据结构中的内容,按照报文格式组装到报文字符串码缓存中并发送,即协议数据结构->字符串码

4.2 RTSP协议请求行数据结构

下面我们来看下协议请求行响应行数据结构具体实现。

代码通过一系列的枚举类型,定义了协议的操作类型、传输方式、版本信息、报文类型等信息,并以此为基础定义了请求行、响应行数据结构。

服务端支持的操作类型

typedef enum __rtsp_msg_method_e 
	RTSP_MSG_METHOD_OPTIONS = 0,//用于查询服务器端可用方法
	RTSP_MSG_METHOD_DESCRIBE,//用于取得媒体描述信息
	RTSP_MSG_METHOD_SETUP,//用于指定建立RTSP会话连接的传输机制
	RTSP_MSG_METHOD_PLAY,//用于请求开始发送数据
	RTSP_MSG_METHOD_RECORD,//用于请求服务端录制指定时间范围媒体数据
	RTSP_MSG_METHOD_PAUSE,//用于暂停RTSP会话
	RTSP_MSG_METHOD_TEARDOWN,//用于结束RTSP会话
	RTSP_MSG_METHOD_ANNOUNCE,//用于把要推送的音视频信息通过sdp格式传给对端
	RTSP_MSG_METHOD_SET_PARAMETER,//用于设置流参数
	RTSP_MSG_METHOD_GET_PARAMETER,//用于获取流参数
	RTSP_MSG_METHOD_REDIRECT,//用于重定向
	RTSP_MSG_METHOD_BUTT,//未匹配到类型
 rtsp_msg_method_e;

rtsp传输方式

typedef enum __rtsp_msg_uri_scheme_e 
	RTSP_MSG_URI_SCHEME_RTSP = 0,//TCP传输
	RTSP_MSG_URI_SCHEME_RTSPU,//UDP传输
	RTSP_MSG_URI_SCHEME_BUTT,//未匹配到类型
 rtsp_msg_uri_scheme_e;

协议url地址

typedef struct __rtsp_msg_uri_s 
	rtsp_msg_uri_scheme_e scheme;//RTSP传输方式
	uint16_t port;//端口号
	char ipaddr[32];//ip地址
	char abspath[64];//url <path>
 rtsp_msg_uri_s;

协议版本

typedef enum __rtsp_msg_version_e 
	RTSP_MSG_VERSION_1_0 = 0,
	RTSP_MSG_VERSION_BUTT,
 rtsp_msg_version_e;

请求行结构

typedef struct __rtsp_msg_request_line_s 
	rtsp_msg_method_e method;//方法
	rtsp_msg_uri_s    uri;//url
	rtsp_msg_version_e version;//版本
 rtsp_msg_request_line_s;

响应行结构

typedef struct __rtsp_msg_response_line_s 
	rtsp_msg_version_e version;//版本
	uint32_t status_code;//状态码
 rtsp_msg_response_line_s;

这里的报文类型增加了RTSP_MSG_TYPE_INTERLEAVED这种类型,表示复用rtsp链路,将rtp/rtcp报文发送到rtsp链路中进行传输,rtp/rtcp不再新建通信链路。

rtsp报文类型

typedef enum __rtsp_msg_type_e 
	RTSP_MSG_TYPE_REQUEST = 0,//rtsp请求报文
	RTSP_MSG_TYPE_RESPONSE,//rtsp应答报文
	RTSP_MSG_TYPE_INTERLEAVED,//rtp/rtcp over rtsp
	RTSP_MSG_TYPE_BUTT,//未匹配到类型
 rtsp_msg_type_e;

rtsp interleaved frame,用于将rtp/rtcp报文发送到rtsp链路中进行传输

typedef struct __rtsp_msg_interleaved_line_s 
	uint8_t  channel;//channel identifier(rtp/rtcp)
	uint16_t length;//the length of rtp/rtcp packet
	uint8_t  reserved;
 rtsp_msg_interleaved_line_s;

4.3 RTSP协议首部行数据结构

rtsp请求-应答序列号

typedef struct __rtsp_msg_cseq_s 
	uint32_t cseq;
 rtsp_msg_cseq_s;

日期

typedef struct __rtsp_msg_date_s 
	char http_date[32];
 rtsp_msg_date_s;

会话id

typedef struct __rtsp_msg_session_s 
	uint32_t session;
 rtsp_msg_session_s;

rtp传输层类型

typedef enum __rtsp_msg_transport_type_e 
	RTSP_MSG_TRANSPORT_TYPE_RTP_AVP = 0,//RTPoverUDP
	RTSP_MSG_TRANSPORT_TYPE_RTP_AVP_TCP,//RTPoverTCP
	RTSP_MSG_TRANSPORT_TYPE_BUTT,
 rtsp_msg_transport_type_e;

header Transport字段

typedef struct __rtsp_msg_transport_s 
	rtsp_msg_transport_type_e type;//rtp传输层类型(tcp/udp)
	uint32_t flags;//以下flag列表实际取值
#define RTSP_MSG_TRANSPORT_FLAG_SSRC			(1<<0)
#define RTSP_MSG_TRANSPORT_FLAG_UNICAST			(1<<1)
#define RTSP_MSG_TRANSPORT_FLAG_MULTICAST		(1<<2)
#define RTSP_MSG_TRANSPORT_FLAG_CLIENT_PORT		(1<<3)
#define RTSP_MSG_TRANSPORT_FLAG_SERVER_PORT		(1<<4)
#define RTSP_MSG_TRANSPORT_FLAG_INTERLEAVED		(1<<5)
	uint32_t ssrc;//rtp ssrc
	uint16_t client_port;//rtcp is rtp + 1
	uint16_t server_port;
	uint8_t interleaved;//rtp/rtcp channel range in rtsp interleaved frame
 rtsp_msg_transport_s;

服务端时间类型结构

typedef enum __rtsp_msg_time_type_e 
	RTSP_MSG_TIME_TYPE_SMPTE = 0,//SMPTE timecode
	RTSP_MSG_TIME_TYPE_NPT,//network time protocol 
	RTSP_MSG_TIME_TYPE_UTC,//Coordinated Universal Time
	RTSP_MSG_TIME_TYPE_BUTT,//未匹配到类型
 rtsp_msg_time_type_e;

SMPTE时间码,主要参数格式是:Hours:Minutes:Second:frames,通常用时间码来识别和记录视频数据流中的每一帧,从一段视频的起始帧到终止帧,其间的每一帧都有一个唯一的时间码地址

typedef struct __rtsp_msg_time_smpte_s 
	//10:07:33:05.01
	uint32_t seconds;	//10*3600 + 07*60 + 33
	uint32_t subframes;	//05*100 + 01
 rtsp_msg_time_smpte_s;

网络时间结构

typedef struct __rtsp_msg_time_npt_s 
	//123.45
	uint32_t secords;//123
	uint32_t usecords;//45
 rtsp_msg_time_npt_s;

协调世界时结构

typedef struct __rtsp_msg_time_utc_s 
	//19961108T142730.25Z
	uint32_t secords;//1996/11/08 14:27:30 - 1900/1/1 0:0:0
	uint32_t usecords;//25 
 rtsp_msg_time_utc_s;

Range Rr opt. PLAY,PAUSE,RECORD 时间范围

typedef struct __rtsp_msg_range_s 
	rtsp_msg_time_type_e type;//服务端时间类型结构
	union __start_u 
		rtsp_msg_time_smpte_s smpte;//SMPTE时间码
		rtsp_msg_time_npt_s npt;//网络时间结构
		rtsp_msg_time_utc_s utc;//协调世界时结构
	 start;//开始时间
	union __end_u 
		rtsp_msg_time_smpte_s smpte;//SMPTE时间码
		rtsp_msg_time_npt_s npt;//网络时间结构
		rtsp_msg_time_utc_s utc;//协调世界时结构
	 end;//结束时间
 rtsp_msg_range_s;

Content-Type类型

typedef enum __rtsp_msg_content_type_e 
	RTSP_MSG_CONTENT_TYPE_SDP = 0,//sdp格式
	RTSP_MSG_CONTENT_TYPE_RTSL,//rtsl格式
	RTSP_MSG_CONTENT_TYPE_MHEG,//mheg格式(Multimedia and Hypermedia Expert Group)
	RTSP_MSG_CONTENT_TYPE_BUTT,
 rtsp_msg_content_type_e;

Accept字段

typedef struct __rtsp_msg_accept_s 
	uint32_t accept;//Accept取值
#define RTSP_MSG_ACCEPT_SDP		(1<<RTSP_MSG_CONTENT_TYPE_SDP)//1<<0
#define RTSP_MSG_ACCEPT_RTSL	(1<<RTSP_MSG_CONTENT_TYPE_RTSL)//1<<1
#define RTSP_MSG_ACCEPT_MHEG	(1<<RTSP_MSG_CONTENT_TYPE_MHEG)//1<<2
 rtsp_msg_accept_s;

Authorization字段

typedef struct __rtsp_msg_authorization_s 
	char authorization[128];
 rtsp_msg_authorization_s;

User-Agent字段

typedef struct __rtsp_msg_user_agent_s 
	char user_agent[64];
 rtsp_msg_user_agent_s;

header public字段

typedef struct __rtsp_msg_public_s 
	uint32_t public_;//header public字段取值
#define RTSP_MSG_PUBLIC_OPTIONS		(1<<RTSP_MSG_METHOD_OPTIONS)//1<<0
#define RTSP_MSG_PUBLIC_DESCRIBE	(1<<RTSP_MSG_METHOD_DESCRIBE)//1<<1
#define RTSP_MSG_PUBLIC_SETUP		(1<<RTSP_MSG_METHOD_SETUP)//1<<2
#define RTSP_MSG_PUBLIC_PLAY		(1<<RTSP_MSG_METHOD_PLAY)//1<<3
#define RTSP_MSG_PUBLIC_RECORD		(1<<RTSP_MSG_METHOD_RECORD)//1<<4
#define RTSP_MSG_PUBLIC_PAUSE		(1<<RTSP_MSG_METHOD_PAUSE)//1<<5
#define RTSP_MSG_PUBLIC_TEARDOWN	(1<<RTSP_MSG_METHOD_TEARDOWN)//1<<6
#define RTSP_MSG_PUBLIC_ANNOUNCE	(1<<RTSP_MSG_METHOD_ANNOUNCE)//1<<7
#define RTSP_MSG_PUBLIC_SET_PARAMETER	(1<<RTSP_MSG_METHOD_SET_PARAMETER)//1<<8
#define RTSP_MSG_PUBLIC_GET_PARAMETER	(1<<RTSP_MSG_METHOD_GET_PARAMETER)//1<<1
#define RTSP_MSG_PUBLIC_REDIRECT	(1<<RTSP_MSG_METHOD_REDIRECT)//1<<10
 rtsp_msg_public_s;

RTP-Info字段结构

typedef struct __rtsp_msg_rtp_subinfo_s 
	rtsp_msg_uri_s url;//__param_u对应的url地址
	uint32_t isseq;
	union __param_u 
		uint32_t rtptime;//rtp时间戳
		uint32_t seq;//rtp流数据包序列号
	 param;
 rtsp_msg_rtp_subinfo_s;

RTP-Info结构队列

typedef struct __rtsp_msg_rtp_info_s 
	uint32_t ninfos;//队列序号
	rtsp_msg_rtp_subinfo_s **info_array;//RTP-Info结构队列指针
 rtsp_msg_rtp_info_s;

Server字段

typedef struct __rtsp_msg_server_s 
	char server[64];
 rtsp_msg_server_s;

Content-Length 实体主体长度

typedef struct __rtsp_msg_content_length_s 
	uint32_t length;
 rtsp_msg_content_length_s;

Content-Type 实体主体类型

typedef struct __rtsp_msg_content_type_s 
	rtsp_msg_content_type_e typeRTSP实时音视频(H264/H265/AAC)开发实战项目

流媒体协议RTMP、RTSP与HLS有啥不同?

计算机网络网络音视频服务- end

计算机网络网络音视频服务- end

实时音视频互动系列(下):基于 WebRTC 技术的实战解析

JavaCV音视频开发宝典:rtsp拉流并使用转码方式转推到rtsp