RTP 协议、RTCP 协议和 H264 的 RTP 打包方法

RTP 协议

RTP(Real-time Transport Protocol)协议,全称是实时传输协议。它主要用于音视频数据的传输。那它的作用是什么呢?

一般我们在实时通信的时候,需要传输音频和视频数据。我们通常是这样做的,先将原始数据经过编码压缩之后,再将编码码流传输到接收端。在传输的时候我们通常不会直接将编码码流进行传输,而是先将码流打包成一个个 RTP 包再进行发送。

那为什么需要打包成 RTP 包呢?这是因为我们的接收端要能够正确地使用这些音视频编码数据,不仅仅需要原始的编码码流,还需要一些额外的信息。比如说:

当前视频码流是哪种视频编码标准,是 H264、H265、VP8、VP9 还是 AV1 呢?我们知道每种不同的编码标准,其码流解析的方式肯定也不一样。这个就需要通过 RTP 协议告知接收端。

当我们知道编码标准了,我们就可以正确地解析码流,并解码出图像了。但是我们又会遇到一个新的问题,那就是按照什么速度播放视频呢?这个也需要 RTP 协议告知接收端。

这就是 RTP 协议的一个重要的作用,即告知接收端一些必要的信息。当然 RTP 协议的作用不止这些,它其实在网络带宽预测和拥塞控制的时候也发挥出了至关重要的作用。我们在之后的课程中会继续讨论,这里就先不讲了,你大体有个印象就可以。

我们知道 RTP 包需要附带很多额外的信息,那这些信息在 RTP 包中是怎么存在的呢?其实 RTP 包包括两个部分:第一个部分是 RTP 头;另外一个部分是 RTP 有效载荷。其中RTP 头主要是用来携带前面说的那些额外信息的,等会儿我会详细介绍一下 RTP 头部每个字段的意义。

这里我先稍微跟你解释一下另外一个部分,也就是 RTP 有效载荷。RTP 有效载荷,其实就是 RTP 包里面的实际数据。如果是 H264 编码打包成 RTP 包,那有效载荷就是经过 H264编码的码流;如果是 VP8 编码呢,那就是 VP8 码流。

接下来,我们重点来看看 RTP 包的头部。具体如下图所示:
在这里插入图片描述
,下面我给了一张表格,你可以对照着表格看看 RTP 包头的每一个字
段占用的位数和具体的含义。其中绿色部分是很重要的知识点,需要你重点掌握。

在这里插入图片描述
上面讲的就是 RTP 头部的主要组成部分。在这里需要单独提一下 RTP 头部的另外一个比较重要的部分,就是 RTP 扩展头。从上表我们可以看到,RTP 包头有一个扩展头标志位X,当扩展头标志位 X 为 1 的时候,说明有 RTP 扩展头。RTP 扩展头由于平时大家很少用看似不怎么重要,但是在 RTC 场景中,尤其是 WebRTC 中经常会用到。另外,RTP 扩展头我们在带宽预测的时候也会用到。所以建议你也了解一下。

扩展头主要是用来给用户自定义扩展使用的。因为协议是标准的,但是用户使用场景却是多种多样的,所以 RTP 需要考虑的比较全面,留了一个扩展头可以让用户根据使用场景和需求,自己定义扩展头,用来传输需要在 RTP 包中传输的信息。扩展头的格式可以参考这篇文章,这里就不做过多的展开了。

以上就是 RTP 协议的主要知识点。有了 RTP 协议,我们就能够将码流打包成 RTP包发给接收端了。如果你只负责传输 RTP 包,而不需要管传输过程中有没有丢包,以及传输 RTP 包的时候有没有引起网络拥塞的话,那你只需要使用 RTP 协议就可以了。比如说,你选择使用 TCP 协议传输 RTP 包的话就可以不用管这些事情,因为 TCP 协议具有丢包重传、拥塞控制等功能。

但是通常情况下,我们在传输音视频数据的时候不会使用 TCP 协议作为传输层协议。这是因为 TCP 协议更适合传输文本和文件等数据,而不适合传输实时音频流和视频流数据,所以我们通常会使用 UDP 协议作为音视频数据的传输层协议。但 UDP 协议不具有丢包重传和拥塞控制的功能,需要我们自己实现。那怎么办呢?

RTCP 协议

RTCP(Real-time Transport Control Protocol)协议,全称是实时传输控制协议。它是辅助 RTP 协议使用的。RTCP 报文有很多种,分别负责不同的功能。常用的报文有发送端报告(SR)、接收端报告(RR)、RTP 反馈报告(RTPFB)等。而每一种报告的有效载荷都是不同的。我们就是通过这些报告在接收端和发送端传递当前统计的 RTP 包的传输情况的。我们使用这些统计信息来做丢包重传,以及预测带宽。

不过,我需要再次强调一下,RTCP 协议只是用来传递 RTP 包的传输统计信息,本身不具有丢包重传和带宽预测的功能,而这些功能需要我们自己来实现。

我们上面讲到了 RTCP 协议有很多种报告,而每种报告其实定义的具体内容都是不一样的。我们这里以 RTPFB 报告中的 NACK 报告(丢包提示报告)作为一个例子来看看 RTCP协议大概是什么样子的。(RTPFB 报告包含了多种子报告,NACK 报告只是其中的一种,因为我们后面还会用到这个报告,所以这里我们就先以这个报告为例子。)

下图就是 NACK 报告的协议格式。
在这里插入图片描述
其中,每一个字段在下表中都有详细的解释。
在这里插入图片描述
我们知道 RTP 是用来传输实际的视频数据的。它就像一个快递盒,先装好视频,然后填好运送的视频基本信息和收件人信息,最后将视频运送到收件人手上。

而 RTCP 协议则像是一个用来统计快递运送情况的记录表。其中的 NACK 报告就是快递丢件情况的记录表。它记录着哪些快递丢了。发件人收到了 NACK 之后,可以重新寄一个同样的快递给收件人,防止收件人没有收到快递。在这里也就是将丢失的视频 RTP 包重传一遍。

虽然我们只讲了一种 RTCP 报告,但是其它的报告也是类似的。大多数报告都是用来记录传输信息的。

H264 RTP 打包

H264 码流是放在 RTP 的有效载荷部分的。因此有效载荷前面的 RTP 头部
跟码流本身是没有关系的,所以我们可以直接先将头部的字段填好就可以。接下来我们需要将 H264 码流填充到 RTP 有效载荷中去。

RTP H264 码流打包分为三种方式:分别是单 NALU 封包方式、组合封包方式、分片封包方式。顾名思义,单 NALU 封包方式是一个 NALU 打一个 RTP 包;而组合封包方式就是多个 NALU 打一个 RTP 包;分片封包方式则是一个 NALU 分开放在连续的多个 RTP 包中。下面我们来分别看一下各种打包方式是怎么样的。

单 NALU 封包方式

单 NALU 封包方式非常简单。我们在 RTP 头部的后面,直接放置 NALU 数据即可。注意,根据 RTP 的规定,这里需要将 NALU 数据前面的起始码去除,不要将起始码也带入RTP 包中。其格式如下:

在这里插入图片描述
为了让你更直观地理解这种打包方式,我给出了打包的示意图。具体如下所示:

在这里插入图片描述
这种打包方式适合于单个 RTP 包小于 1500 字节(MTU 大小)的时候。一般来说,一些P 帧和 B 帧编码之后比较小,就可以使用这种打包方式。

组合封包方式

组合封包方式稍微复杂一些。它是将多个 NALU 放置在一个 RTP 包中。在 RTP 头部之后,且放置 NALU 数据之前,我们需要放置一个 1 字节的 STAP-A 的头部。其中,STAPA Header 跟 NALU Header 的格式是一样的,只是 Type 字段的值不一样。因此,你可以参考 H264 码流结构课程中 NALU 小节来理解 STAP-A 的头部的格式。具体如下图所示:

在这里插入图片描述
其中,Type 的取值如下表所示。这里我需要提醒你一下,表中的 24 和 25 类型就是STAP 组合封包方式。注意,我们这里只讲 STAP-A,这是因为 STAP-B 很少用到。

在这里插入图片描述
放置完 STAP-A Header 之后,在每一个 NALU 的前面我们需要放置一个 2 字节的 size字段,用于表示后面的 NALU 的大小。之后才是 NALU 的数据。记住同样需要去掉起始码。其格式如下:

在这里插入图片描述
同样地,为了让你更直观地理解这种打包方式,我也给出了打包的示意图。具体如下所示:

在这里插入图片描述
这种打包方式适合于单个 NALU 很小的时候。因此,我们将多个 NALU 打包到一起也小于1500 字节的时候就可以使用。但是由于一般多个视频帧加到一起还小于 1500 的情况比较少,所以视频数据的 RTP 打包一般来说用组合封包方式的情况也很少。

分片封包方式

经常用到的打包方式。
它是将一个 NALU 分开打包在连续的多个 RTP 包中。因此,我们首先需要一个 1 字节的FU indicator 来表示当前 RTP 包是不是分片封包方式,再用一个 1 字节的 FU Header 来表示当前这个 RTP 包是不是 NALU 的第一个包,是不是 NALU 的最后一个包,以及NALU 的类型。

为什么需要表示是不是第一个包以及是不是最后一个包呢?这是因为一个 NALU 被分开放在多个 RTP 包中,我们需要知道哪个是第一个 NALU 分片,哪个是最后一个 NALU 分片,以及哪些是中间分片。这样我们才能组成一个完整的 NALU。

那你可能会问,NALU 不是已经在 NALU Header 中有了 NALU Type 字段吗?为什么 FU Header 中还要有 NALU Type 呢?这是因为分片封包时需要去掉 NALU Header。因此,我们需要通过 FU Header 中的 NALU Type 得到 NALU 的类型。

其中,分片封装中的 FU indicator 跟 NALU Header 的格式也是一样的,也只是 Type 字段的值不同,所以我们可以参考组合封包小节中的表格。因为我们一般只使用 FU-A,所以接下来讲述的将是 FU-A 的分片封包方式。另外,FU Header 格式如下所示:

在这里插入图片描述
这里我简单解释一下各字段的含义:

S:起始位,占 1bit,为 1 则表示是 NALU 的第一个 RTP 包。
E:结束位,占 1bit,为 1 则表示是 NALU 的最后一个 RTP 包。
R:预留位,占 1bit。
Type:占 5bits,表示 NALU 类型。

分片打包的格式如下:
在这里插入图片描述
分片打包的示意图如下:
在这里插入图片描述
这种打包方式主要用于将 NALU 数据打包成一个 RTP 包时大小大于 1500 字节的时候,这是经常使用的视频 RTP 打包方法。

我们怎么选择使用哪种方式打包呢?一般来说,我们在一个 H264 码流中会混合使用多种 RTP 打包方式。一般来说,对于小的 P 帧、B 帧还有
SPS、PPS 我们可以使用单个 NALU 封包方式。而对于大的 I 帧、P 帧或 B 帧,我们使用分片封包方式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Learning together

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值