RTSP工作过程,H264码流封装

在学习进行视频编解码以及推拉流的过程中,搜索相关资料比较少,不是很完整,搜集整理了一些内容,备注出处,如有遗漏可留言联系。 

1. rtsp协议简介

2. 流媒体SDP格式详解

3. RTP理解

4. RTCP理解

5. H264码流进行RTP封装

1. rtsp协议简介

参考原始博客链接

1.1. RTSP简介

rtsp,英文全称 Real Time Streaming Protocol,RFC2326,实时流传输协议,是TCP/IP协议体系中的一个应用层协议!协议主要规定定了一对多应用程序如何有效地通过IP网络传送多媒体数据。RTSP体系结位于RTP和RTCP之上(RTCP用于控制传输,RTP用于数据传输),使用TCP或UDP完成数据传输!

RTSP是一个实时传输流协议,是一个应用层的协议。通常说的RTSP 包括RTSP协议、RTP协议、RTCP协议,对于这些协议的作用简单的理解如下:

RTSP协议:负责服务器与客户端之间的请求与响应

RTP协议: 负责服务器与客户端之间传输媒体数据

RTCP协议:负责提供有关RTP传输质量的反馈,就是确保RTP传输的质量

三者的关系: rtsp并不会发送媒体数据,只是完成服务器和客户端之间的信令交互,rtp协议负责媒体数据传输,rtcp负责rtp数据包的监视和反馈。rtp和rtcp并没有规定传输层的类型,可以选择udp和tcp。Rtsp的传输层则要求是基于tcp。

1.2. RTSP推流步骤

RTSP(Real-Time Streaming Protocol)推流是指使用RTSP协议将音视频数据从源端推送到RTSP服务器或其他接收端的过程。下面是RTSP推流的主要步骤:

1. 准备音视频源:首先,需要有一个音视频源,可以是摄像头、视频文件或其他实时音视频流。这个源将提供实时的音视频数据。

2. 建立RTSP连接:客户端应用程序通过建立与RTSP服务器的TCP连接来初始化RTSP会话。通常,客户端使用RTSP的SETUP命令发送请求,指定要推送的媒体流的URL、传输协议和端口等参数。

3. 媒体描述和协商:一旦建立了RTSP连接,客户端发送DESCRIBE命令请求服务器提供媒体流的描述信息。服务器会回复一个包含媒体流相关信息的SDP(Session Description Protocol)描述。

4. 建立媒体传输会话:客户端使用SETUP命令来建立媒体传输会话。该命令指定了媒体流的传输方式、协议、端口和传输地址等。服务器在收到SETUP请求后,会为媒体流分配相应的资源,并返回相应的响应。

5. 传输音视频数据:一旦媒体传输会话建立成功,客户端可以开始推送音视频数据。通常,客户端使用RTP(Real-Time Transport Protocol)或其他类似协议将音视频数据封装并通过指定的传输地址和端口发送到服务器。

6. 控制和同步:客户端可以使用PLAY、PAUSE、TEARDOWN等命令来控制媒体流的播放、暂停和结束。这些命令通过RTSP协议发送到服务器,服务器根据命令执行相应的操作。

7. 结束推流:当需要结束推流时,客户端可以发送TEARDOWN命令通知服务器关闭媒体传输会话。服务器收到命令后会释放相关资源并回复相应的响应。

需要注意的是,RTSP推流的具体实现可能因使用的服务器软件、编码格式、网络传输协议等而有所不同。在实际应用中,需要根据的具体需求和环境进行相应的配置和调整。

此外,RTSP推流还需要考虑网络带宽、延迟、传输协议选择等因素,以确保音视频数据能够实时、稳定地传输到目标接收端。

假设我们现在要向一个RTSP的sever发送请求获取数据,基本流程如下:

OPTIONS

C—>S

客户端向服务器端发送OPTIONS,请求可用的方法。

S—>C

服务器端回复客户端,消息中包含当前可用的方法。

DESCRIBE

C—>S

客户端向服务器请求媒体描述文件,一般通过rtsp开头的url来发起请求,格式为sdp。

S—>C

服务器回复客户端sdp文件,该文件告诉客户端服务器有哪些音视频流,有什么属性,如编解码器信息,帧率等。

SETUP

C—>S

客户端向服务器端发起建立连接请求,请求建立会话连接,准备开始接收音视频数据,请求信息描述了期望音视频数据包基于UDP还是TCP传输,指定了RTP,RTCP端口,以及是单播还是组播等信息!

S—>C

服务器端收到客户端请求后,根据客户端请求的端口号确定发送控制数据的端口以及音视频数据的端口!

PLAY

C—>S

客户端向服务端请求播放媒体。

S—>C

服务器回复客户端200 OK! 之后开始通过SETUP中指定的端口开始发送数据!

TEARDOWN

C---->S

结束播放的时候,客户端向服务器端发起结束请求

S—>C

服务端收到消息后,向客户端发送200 OK,之后断开连接

上述的流程基本涵盖了RTSP的流程,当然,RTSP除此之外,还有PAUSE,SCALE,GET_PARAMETER,SET_PARAMETER等参数。

RTSP消息分为两大类,一类是请求消息(request),一类是回应消息(ressponse)

1.3. 请求报文

请求消息的格式如下:

也就是说:

方法 URI RTSP版本 CRLF

消息头 CRLF CRLF

消息体 CRLF

1.3.1. 请求消息的第一行的语法结构如下:

Request-Line = Method 空格 Request-URI 空格 RTSP-Version CRLF

其中方法包括OPIONS、DESCRIBE、SETUP、PLAY、TEARDOWN等,URI是接受方的地址,例如:rtsp://192.168.0.1/video1.3gp。

RTSP版本一般都是 RTSP/1.0。每行后面的CRLF表示回车换行,需要接受端有相应的解析,

1.3.2. 在消息头中除了第一行的内容外,还有一些需求提供附加信息。其中有些是一定要的。

消息头 = Accept

| Accept-Encoding

| Accept-Language

| Authorization

| From

| If-Modified-Since

| Range

| Referer

| User-Agent

1.3.3. 最后一个消息头需要有两个CRLF。消息体是可选的,有的Request消息并不带消息体。

比如:该RTSP请求消息的方法为OPTIONS,请求的目标地址为rtsp://192.17.1.63:554,RTSP的版本为1.0;

接下来包含两种类型的消息:

第一种为CSeq表示序列号,本次请求的序列号为1(服务器端回复此请求的数据包的序列号也是1);

第二种为User-Agent,表示用户代理,值为“Lavf58.42.100”;

由于User-Agent为最后一条消息,其后要跟两组回车和换行!

用户代理为LibVLC/2.2.4,使用VLC播放器rtsp流的一个代理。

1.4. 响应报文

响应报文的开始行是状态行,RTSP响应报文的结构如下图所示

也就是说:回应消息由 RTSP版本+状态码+解释开头(之后跟一条或多条消息)

RTSP版本 状态码 解释 CRLF

消息头 CRLF CRLF

消息体 CRLF

说明:

状态码:表示状态,同http的返回状态,如200,表示OK

解释:针对状态码的文本解释

同样:最后一条消息也是需要 跟两个回车和换行!

回复消息以Response标识,该消息中RTSP的版本号为1.0;

服务器回复的状态码为401;

针对状态码401的解释为Unauthorized(未授权);

包含两种类型的消息:

一是WWW-Authenticate:告诉请求端授权认证需要的信息;

二是Date:表示当前日期和时间!

2. 流媒体SDP格式详解

2.1. 概述

SDP协议,全称Session Description Protocol,翻译过来就是会话描述协议,在流媒体通信中负责携带媒体信息,这样通信双方能够协商好双方具有的媒体能力。通常SDP会荷载到其他信令协议中入:SIP、RTSP,其中WebRTC中没有明确规定信令协议,但会荷载到offer、answer报文中。


PS:什么是会话:比如一次网络电话、一次电话会议、一次视频聊天,这些都可以称之为一次会话。

2.2. 作用

SDP在webrtc或voip通话中有重要的作用,它通过文本对媒体信息进行描述。其本身并不传递媒体数据,而是用于参与媒体会话的双方进行媒体协商。通过SDP,通信双方可以知道对方的:支持的音视频编码器、网络信息以及其他重要信息。在webrtc中没有规定统一的信令,通常信令使用使用者自己实现,下图是webrtc中sdp的作用:

highlighting text

2.3. 格式规范

多个媒体级描述

  • 媒体格式
  • 传输协议
  • 纯属IP和端口
  • 媒体负载类型

一个会话级描述

  • 会话的名称和目的
  • 会话存活时间
  • 会话中包括多个媒体信息

格式:type=value组成

2.3.1. 会话层

v=(协议版本)

o=(所有者/创建者和会话标识符)

s=(会话名称)

c= * (连接信息 ― 如果包含在所有媒体中,则不需要该字段)

t=会话存活时间

a = * (0 个或多个会话属性行)

ps:(带星号的是可选字段,不带的是必选)

2.3.2. 媒体层

m=(媒体名称和传输地址)

c=*(连接信息 ― 如果包含在所有媒体中,则不需要该字段)

b=*(带宽信息)

a = * (0 个或多个会话属性行)

字段含义详解:

1、version 必选

2、session name 必选

s= [sission name] 会话名,s=-表示忽略会话

3、origion/owner 必选

o=<username> <sess-id> <sess-version> <nettype> <addrtype> <unicast-address>

例子:o=- 6474257184349789314 2 IN IP4 127.0.0.1

4、connection 可选

c=<network type><address type><connection address>

例子:c=IN IP4 0.0.0.0

5、media 必须

m=<media><port><transport><fmt/payload type list>

例子:m=audio 9 UDP/TLS/RTP/SAVPF 111 63 103 104 9 0 8 106 105 13 110 112 113 126

6、attributes 可选

a=<TYPE> 或a=<TYPE>:<VALUE>

例子:a=frameate:<帧速率>

7、rtpmap 可选(重要)

a=rtpmap:<fmt/payload type><encoding name>/<clock rate>[/<encodingparameters>]

例子:a=rtpmap:111 opus/48000/2

8、fmtp 可选

a=fmtp:<format/payload type> paramerters

例子:a=fmtp:101 apt=100

3. RTP理解

参考链接:RTP理解-CSDN博客

  1. RTP:实时传输协议(Real-time Transport Protocol或简写RTP)是一个网络传输协议。
  2. RTP定义了两种报文:RTP报文RTCP报文
  3. RTP报文用于传送媒体数据(如音频和视频),它由 RTP报头数据两部分组成,RTP数据部分称为有效载荷(payload);
  4. RTCP报文用于传送控制信息,以实现协议控制功能。
  5. RTP报文和RTCP 报文将作为下层协议的数据单元进行传输。
  6. 如果使用UDP,则RTP报文和RTCP报文分别使用两个相邻的UDP端口,RTP报文使用低端口,RTCP报文使用高端口。
  7. 如果使用其它的下层协议,RTP报文和RTCP报文可以合并,放在一个数据单元中一起传送,控制信息在前,媒体数据在后。
  8. 通常,RTP是由应用程序实现的。

3.1. RTP的会话过程

当应用程序建立一个RTP会话时,应用程序将确定一对目的传输地址。目的传输地址由一个网络地址和一对端口组成,有两个端口:一个给RTP包,一个给RTCP包,使得RTP/RTCP数据能够正确发送。RTP数据发向偶数的UDP端口,而对应的控制信号RTCP数据发向相邻的奇数UDP端口(偶数的UDP端口+1),这样就构成一个UDP端口对。 RTP的发送过程如下,接收过程则相反。

  1. RTP协议从上层接收流媒体信息码流(如H.263),封装成RTP数据包;RTCP从上层接收控制信息,封装成RTCP控制包。
  2. RTP将RTP 数据包发往UDP端口对中偶数端口;RTCP将RTCP控制包发往UDP端口对中的接收端口。

3.2. RTP概述图

从图中可以看出,RTP被划分在传输层,它建立在UDP上。同UDP协议一样,为了实现其实时传输功能,RTP也有固定的封装形式。

RTP用来为端到端的实时传输提供时间信息和流同步,但并不保证服务质量。服务质量由RTCP来提供。

不少人也把RTP归为应用层的一部分,这是从应用开发者的角度来说的。操作系统中的TCP/IP等协议栈所提供的是我们最常用的服务,而RTP的实现还是要靠开发者自己。因此从开发的角度来说,RTP的实现和应用层协议的实现没不同,所以可将RTP看成应用层协议。

RTP实现者在发送RTP数据时,需先将数据封装成RTP包,而在接收到RTP数据包,需要将数据从RTP包中提取出来。

3.3. RTP报文格式

RTP报文由两部分组成:报头和有效载荷。

RTP报头格式其中:
V:version,RTP协议的版本号,占2位,当前协议版本号为2。
P:padding,填充标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。
X:extension,扩展标志,占1位,如果X=1,则在RTP报头后跟有一个扩展报头。
CC:csrcLen,CSRC计数器,占4位,指示CSRC 标识符的个数。
M: marker,标记,占1位,不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。

PT: payloadType,有效载荷类型,占7位,用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等。
序列号:seq,占16位,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。接收者通过序列号来检测报文丢失情况,重新排序报文,恢复数据。
时戳:timestamp,占32位,时戳反映了该RTP报文的第一个八位组的采样时刻。接收者使用时戳来计算延迟和延迟抖动,并进行同步控制。

同步信源(SSRC)标识符:占32位,用于标识同步信源。该标识符是随机选择的,参加同一视频会议的两个同步信源不能有相同的SSRC。
特约信源(CSRC)标识符:每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源。

3.3.1. RTP头的结构体

struct RtpHeader
{
    /* byte 0 *由上至下,由低位开始填充*/
    uint8_t csrcLen : 4;//CSRC计数器,占4位,指示CSRC 标识符的个数。
    uint8_t extension : 1;//占1位,如果X=1,则在RTP报头后跟有一个扩展报头。
    uint8_t padding : 1;//填充标志,占1位,如果P=1,则在该报文的尾部填充一个或多个额外的八位组,它们不是有效载荷的一部分。
    uint8_t version : 2;//RTP协议的版本号,占2位,当前协议版本号为2。

    /* byte 1 */
    uint8_t payloadType : 7;//有效载荷类型,占7位,用于说明RTP报文中有效载荷的类型,如GSM音频、JPEM图像等。
    uint8_t marker : 1;//标记,占1位,不同的有效载荷有不同的含义,对于视频,标记一帧的结束;对于音频,标记会话的开始。

    /* bytes 2,3 */
    uint16_t seq;//占16位,用于标识发送者所发送的RTP报文的序列号,每发送一个报文,序列号增1。接收者通过序列号来检测报文丢失情况,重新排序报文,恢复数据。

    /* bytes 4-7 */
    uint32_t timestamp;//占32位,时戳反映了该RTP报文的第一个八位组的采样时刻。接收者使用时戳来计算延迟和延迟抖动,并进行同步控制。

    /* bytes 8-11 */
    uint32_t ssrc;//占32位,用于标识同步信源。该标识符是随机选择的,参加同一视频会议的两个同步信源不能有相同的SSRC。

   /*标准的RTP Header 还可能存在 0-15个特约信源(CSRC)标识符
   
   每个CSRC标识符占32位,可以有0~15个。每个CSRC标识了包含在该RTP报文有效载荷中的所有特约信源

   */
};

3.3.2. RTP包的结构体

struct RtpPacket
{
    struct RtpHeader rtpHeader;
    uint8_t payload[0];
};
// 包含一个RTP头部和RTP载荷

4. RTCP理解

参考链接:RTP理解-CSDN博客

当应用程序开始一个rtp会话时将使用两个端口:一个给rtp,一个给rtcp。

rtp本身并不能为按顺序传送数据包提供可靠的传送机制,也不提供流量控制或拥塞控制,它依靠rtcp提供这些服务。

在rtp的会话之间周期的发放一些rtcp包以用来传监听服务质量和交换会话用户信息等功能。

rtcp包中含有已发送的数据包的数量、丢失的数据包的数量等统计资料。

因此,服务器可以利用这些信息动态地改变传输速率,甚至改变有效载荷类型。

rtp和rtcp配合使用,它们能以有效的反馈和最小的开销使传输效率最佳化,因而特别适合传送网上的实时数据。

根据用户间的数据传输反馈信息,可以制定流量控制的策略,而会话用户信息的交互,可以制定会话控制的策略。

4.1. RTCP报文格式

在RTCP通信控制中,RTCP协议的功能是通过不同的RTCP数据报来实现的,主要有如下几种类型:
①SR:发送端报告,所谓发送端是指发出RTP数据报的应用程序或者终端,发送端同时也可以是接收端。
②RR:接收端报告,所谓接收端是指仅接收但不发送RTP数据报的应用程序或者终端。
③SDES:源描述,主要功能是作为会话成员有关标识信息的载体,如用户名、邮件地址、电话号码等,此外还具有向会话成员传达会话控制信息的功能。
④BYE:通知离开,主要功能是指示某一个或者几个源不再有效,即通知会话中的其他成员自己将退出会话。
⑤APP:由应用程序自己定义,解决了RTCP的扩展性问题,并且为协议的实现者提供了很大的灵活性。

4.2. RTCP的封装

RTCP也是用UDP来传送的,但RTCP封装的仅仅是一些控制信息,因而分组很短,所以可以将多个RTCP分组封装在一个UDP包中。RTCP有如下五种分组类型

4.2.1. SR类型

发送端报告分组SR(Sender Report)用来使发送端以多播方式向所有接收端报告发送情况。SR分组的主要内容有:相应的RTP流的SSRC,RTP流中最新产生的RTP分组的时间戳和NTP,RTP流包含的分组数,RTP流包含的字节数。SR包的封装如图所示

版本(V):同RTP包头域。
填充(P):同RTP包头域。
接收报告计数器(RC):5比特,该SR包中的接收报告块的数目,可以为零。
包类型(PT):8比特,SR包是200。
长度域(Length):16比特,其中存放的是该SR包以32比特为单位的总长度减一。
同步源(SSRC):SR包发送者的同步源标识符。与对应RTP包中的SSRC一样。
NTP Timestamp(Network time protocol)SR包发送时的绝对时间值。NTP的作用是同步不同的RTP媒体流。
RTP Timestamp:与NTP时间戳对应,与RTP数据包中的RTP时间戳具有相同的单位和随机初始值。
Sender’s packet count:从开始发送包到产生这个SR包这段时间里,发送者发送的RTP数据包的总数. SSRC改变时,这个域清零。
Sender`s octet count:从开始发送包到产生这个SR包这段时间里,发送者发送的净荷数据的总字节数(不包括头部和填充)。发送者改变其SSRC时,这个域要清零。
同步源n的SSRC标识符:该报告块中包含的是从该源接收到的包的统计信息。
丢失率(Fraction Lost):表明从上一个SR或RR包发出以来从同步源n(SSRC_n)来的RTP数据包的丢失率。
累计的包丢失数目:从开始接收到SSRC_n的包到发送SR,从SSRC_n传过来的RTP数据包的丢失总数。
收到的扩展最大序列号:从SSRC_n收到的RTP数据包中最大的序列号。
接收抖动(Interarrival jitter):RTP数据包接受时间的统计方差估计。
上次SR时间戳(Last SR,LSR):取最近从SSRC_n收到的SR包中的NTP时间戳的中间32比特。如果目前还没收到SR包,则该域清零。
上次SR以来的延时(Delay since last SR,DLSR):上次从SSRC_n收到SR包到发送本报告的延时。

5. H264码流进行RTP封装

5.1. H.264基本编码格式

H.264由一个一个的NALU组成,每个NALU之间使用00 00 00 01或00 00 01分隔开,每个NALU的第一次字节都有特殊的含义。

  1. F(forbiden):禁止位,占用NAL头的第一个位,当禁止位值为1时表示语法错误。
  2. NRI:参考级别,占用NAL头的第二到第三个位;值越大,该NAL越重要。
  3. Type:Nal单元数据类型,也就是标识该NAL单元的数据类型是哪种,占用NAL头的第四到第8个位。

常用Nalu_type:

0x06 (0 00 00110) SEI type = 6

0x67 (0 11 00111) SPS type = 7

0x68 (0 11 01000) PPS type = 8

0x65 (0 11 00101) IDR type = 5

0x65 (0 10 00101) IDR type = 5

0x65 (0 01 00101) IDR type = 5

0x65 (0 00 00101) IDR type = 5

0x61 (0 11 00001) I帧 type = 1

0x41 (0 10 00001) P帧 type = 1

0x01 (0 00 00001) B帧 type = 1

对于H.264格式了解这些就够了,我们的目的是想从一个H.264的文件中将一个一个的NALU提取出来,然后封装成RTP包,下面介绍如何将NALU封装成RTP包。

5.2. H.264三种RTP打包方式

  1. 单NALU打包: 一个RTP包包含一个完整的NALU。
  2. 聚合打包:对于较小的NALU,一个RTP包可包含多个完整的NALU。
  3. 分片打包:对于较大的NALU,一个NALU可以分为多个RTP包发送。

注意:这里要区分好概念,每一个RTP包都包含一个RTP头部和RTP荷载,这是固定的。而H.264发送数据可支持三种RTP打包方式。

比较常用的是单NALU打包和分片打包。

5.2.1. 单NALU打包

所谓单NALU打包就是将一整个NALU的数据放入RTP包的载荷中,这是最简单的一种方式。

5.2.2. 分片打包

RTP一般都是使用UDP发送,UDP没有流量控制,但每个RTP包都有大小限制的,所以要限制每一次发送的大小。如果一个H264文件的NALU的太大,就需要分成多个RTP包发送,如何分成多个RTP包,如下:

  1. 首先要明确,RTP包的格式是绝不会变的,永远多是RTP头+RTP载荷:

  1. RTP头部是固定的,那么只能在RTP载荷中去添加额外信息来说明这个RTP包是表示同一个NALU

如果是分片打包的话,那么在RTP载荷开始有两个字节的信息,然后再是NALU的内容

  1. 第一个字节位FU Indicator,其格式如下:

高三位:与NALU第一个字节的高三位相同

Type:28,表示该RTP包一个分片,为什么是28?因为H.264的规范中定义的,此外还有许多其他Type,这里不详讲。

  1. 第二个字节位FU Header,其格式如下:

S:标记该分片打包的第一个RTP包

E:比较该分片打包的最后一个RTP包

Type:NALU的Type。

  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值