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->S | OPTION request | 询问对端有哪些可用方法 | OPTION用于查询服务器端可用方法 |
S->C | OPTION response | 回应S所有可用方法 | |
C->S | DESCRIBE request | 取得S媒体描述信息 | DESCRIBE用于取得媒体描述信息 |
S->C | DESCRIBE response | 回应媒体描述信息 | |
C->S | SETUP request | 请求建立会话连接 | SETUP用于建立RTSP会话连接 |
S->C | SETUP response | 建立会话连接 | |
C->S | PLAY request | C请求S开始发送数据 | PLAY用于请求开始发送数据 |
S->C | PLAY response | S回应该请求的信息 | |
C->S | TEARDOWN request | 请求关闭会话 | TEARDOWN用于结束RTSP会话 |
S->C | TEARDOWN response | S回应退出请求 |
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这三个操作中的作用范围。
Header | type | support | methods |
---|---|---|---|
Accept | R | opt. | entity |
Accept-Encoding | R | opt. | entity |
Accept-Language | R | opt. | all |
Allow | r | opt. | all |
Authorization | R | opt. | all |
Bandwidth | R | opt. | all |
Blocksize | R | opt. | all but OPTIONS, TEARDOWN |
Cache-Control | g | opt. | SETUP |
Conference | R | opt. | SETUP |
Connection | g | req. | all |
Content-Base | e | opt. | entity |
Content-Encoding | e | req. | SET_PARAMETER |
Content-Encoding | e | req. | DESCRIBE, ANNOUNCE |
Content-Language | e | req. | DESCRIBE, ANNOUNCE |
Content-Length | e | req. | SET_PARAMETER, ANNOUNCE |
Content-Length | e | req. | entity |
Content-Location | e | opt. | entity |
Content-Type | e | req. | SET_PARAMETER, ANNOUNCE |
Content-Type | r | req. | entity |
CSeq | g | req. | all |
Date | g | opt. | all |
Expires | e | opt. | DESCRIBE, ANNOUNCE |
From | R | opt. | all |
If-Modified-Since | R | opt. | DESCRIBE, SETUP |
Last-Modified | e | opt. | entity |
Proxy-Require | R | req. | all |
Public | r | opt. | all |
Range | R | opt. | PLAY, PAUSE, RECORD |
Range | r | opt. | PLAY, PAUSE, RECORD |
Referer | R | opt. | all |
Require | R | req. | all |
Retry-After | r | opt. | all |
RTP-Info | r | req. | PLAY |
Scale | Rr | opt. | PLAY, RECORD |
Session | Rr | req. | all but SETUP, OPTIONS |
Server | r | opt. | all |
Speed | Rr | opt. | PLAY |
Transport | Rr | req. | SETUP |
Unsupported | r | req. | all |
User-Agent | R | opt. | all |
Via | g | opt. | all |
WWW-Authenticate | r | opt. | 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 type;//Content-Type类型类型
} rtsp_msg_content_type_s;
4.3 RTSP协议报文数据结构
将协议请求行、响应行、首部行等数据结构再进一步封装,就得到了用于描述rtsp报头信息的rtsp_msg_hdr_s、描述rtsp报文实体主体的rtsp_msg_body_s,以及最终描述rtsp报文信息的rtsp_msg_s结构。
rtsp报头结构 message header
typedef struct __rtsp_msg_hdr_s {
union __start_line_u {
rtsp_msg_request_line_s reqline;//请求行
rtsp_msg_response_line_s resline;//响应行
rtsp_msg_interleaved_line_s interline;//rtsp interleaved frame
} startline;//开始行
//general-headers field 通用首部字段
rtsp_msg_cseq_s *cseq;//序列号
rtsp_msg_date_s *date;//日期
rtsp_msg_session_s *session;//会话id
rtsp_msg_transport_s *transport;//header Transport字段
rtsp_msg_range_s *range;//时间范围
//request-headers field 请求首部字段
rtsp_msg_accept_s *accept;//header Accept字段
rtsp_msg_authorization_s *authorization;//header Authorization字段
rtsp_msg_user_agent_s *user_agent;//header User-Agent字段
//response-headers field 响应首部字段
rtsp_msg_public_s *public_;//header public字段
rtsp_msg_rtp_info_s *rtp_info;//header RTP-Info字段
rtsp_msg_server_s *server;//header Server字段
//entity-headers field 实体主体首部字段
rtsp_msg_content_length_s *content_length;//header Content-Length 实体主体长度
rtsp_msg_content_type_s *content_type;//header Content-Type 实体主体类型
} rtsp_msg_hdr_s;
rtsp报文实体主体
typedef struct __rtsp_msg_body_s {
void *body;//报文实体主体指针
} rtsp_msg_body_s;
rtsp报文结构
typedef struct __rtsp_msg_s {
rtsp_msg_type_e type;//报文类型
rtsp_msg_hdr_s hdrs;//报头结构
rtsp_msg_body_s body;//实体主体
} rtsp_msg_s;
至此,我们通过一系列的结构体,完成了对协议报文结构的描述。通过下面的方法,从网络接口中读取报文并解析到报文结构体对象中,或从报文结构体对象中提取报文信息并组装发送到网络接口,完成与客户端的交互。
int rtsp_msg_set_request (rtsp_msg_s *msg, rtsp_msg_method_e mt, const char *ipaddr, const char *abspath);
int rtsp_msg_set_response (rtsp_msg_s *msg, int status_code);
int rtsp_msg_get_cseq (const rtsp_msg_s *msg, uint32_t *cseq);
int rtsp_msg_set_cseq (rtsp_msg_s *msg, uint32_t cseq);
int rtsp_msg_get_session (const rtsp_msg_s *msg, uint32_t *session);
int rtsp_msg_set_session (rtsp_msg_s *msg, uint32_t session);
int rtsp_msg_get_date (const rtsp_msg_s *msg, char *date, int len);
int rtsp_msg_set_date (rtsp_msg_s *msg, const char *date);
int rtsp_msg_set_transport_udp (rtsp_msg_s *msg, uint32_t ssrc, int client_port, int server_port);
int rtsp_msg_set_transport_tcp (rtsp_msg_s *msg, uint32_t ssrc, int interleaved);
int rtsp_msg_get_accept (const rtsp_msg_s *msg, uint32_t *accept);
int rtsp_msg_set_accept (rtsp_msg_s *msg, uint32_t accept);
int rtsp_msg_get_user_agent (const rtsp_msg_s *msg, char *user_agent, int len);
int rtsp_msg_set_user_agent (rtsp_msg_s *msg, const char *user_agent);
int rtsp_msg_get_public (const rtsp_msg_s *msg, uint32_t *public_);
int rtsp_msg_set_public (rtsp_msg_s *msg, uint32_t public_);
int rtsp_msg_get_server (const rtsp_msg_s *msg, char *server, int len);
int rtsp_msg_set_server (rtsp_msg_s *msg, const char *server);
int rtsp_msg_get_content_type (const rtsp_msg_s *msg, int *type);
int rtsp_msg_set_content_type (rtsp_msg_s *msg, int type);
int rtsp_msg_get_content_length (const rtsp_msg_s *msg, int *length);
int rtsp_msg_set_content_length (rtsp_msg_s *msg, int length);
uint32_t rtsp_msg_gen_session_id (void);
小结
本篇为流媒体开发系列文章的第二篇,通过引入http协议,介绍了rtsp协议报文格式,通过抓包分析了报文交互流程,并最终结合代码探讨背后的实现机制。
在下一篇文章中,我们会结合rtsp报文数据结构以及4.3节中提到的方法,讲述如果对请求报文进行解析,以及如何根据报文数据结构组织应答报文,欢迎大家继续关注。
往期推荐
ffmpeg播放器实现详解 - FFmpeg编译安装
ffmpeg播放器实现详解 - FFPlay源码编译
ffmpeg播放器实现详解 - 框架搭建
ffmpeg播放器实现详解 - 视频显示
ffmpeg播放器实现详解 - 音频播放
ffmpeg播放器实现详解 - 创建线程
ffmpeg播放器实现详解 - 视频同步控制
ffmpeg播放器实现详解 - 音频同步控制
ffmpeg播放器实现详解 - 快进快退控制
// 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
// 公众号:断点实验室
// 扫描二维码,关注更多优质原创,内容包括:音视频开发、图像处理、网络、
// Linux,Windows、Android、嵌入式开发等
![](https://img2020.cnblogs.com/blog/2063669/202006/2063669-20200624225442115-995290456.jpg)