在工作中经常与RTP打交道,在这里总结一点工作经常使用和注意的地方。

基本概念

RTP(Real-time Transport Protocol,实时传输协议)是一种用于在IP网络中传输多媒体数据的协议,由IETF(Internet Engineering Task Force)制定。其主要功能是提供端到端的实时数据传输服务,特别适用于音频、视频等多媒体数据的传输。

RTP协议基于多播或单播进行连续传输媒体数据的实时传输服务,RTP通常与RTCP配合使用,RTP主要负责实时数据的传输,而RTCP则负责监控传输质量、提供控制信息和管理会话参与者的信息,RTCP通过周期性地发送统计信息和反馈报告,帮助RTP调整传输速率和解决网络拥塞问题。由于TCP需要较多的开销不适合传输实时数据,一般采用RTP/UDP来传输实时媒体数据(也可以用UDP/TCP)。

RTP传输H264数据的过程如下:

RTP封装H264

RTP报文

RTP报文由两部分组成:报头+有效负载(H264数据),RTP报头格式如下:

V:版本号,2比特,用来标志使用的RTP版本;

P:填充位,1比特,如果P=1,则在报文尾部将填充一个或多个额外的八位组,它们不是有效载荷的一部分。

X:扩展位,1比特,如果X=1,则在RTP头部后跟有扩展头(有些多路视频源的场合可以使用)。

CC:CSRC计数器,4比特,指示CSRC标识符的个数。主要用于多流组合传播,比如说有x个人发送RTP到网关边缘,边缘会把这x个RTP转发给另一个边缘,然后解码出原始流。

M:标记位,1比特,对于视频来说表示一帧的结束,对于音频标记会话的开始。

PT:载荷类型,7比特,标识RTP载荷的类型。

SN:序列号,16比特,标识发送这发送的RTP报文的序列号,每发送一个报文,序列号+1,接收者通过序列号检测报文丢失情况,重新排序报文,恢复数据。

TimeStamp:时间戳,32位,记录了包中数据的第一个字节的采样时刻,即使没有没有信号发送时,时间戳的数值也会不断增加,时间戳主要作用是计算延迟和延迟抖动,进行同步控制这些。

SSRC:同步源标识符,32位,指RTP包的来源,同一个会话不会有两个一样的,MD5算法生成。

CSRC:特约信源,每一个占32位,可以有0~15个,标识了包含在RTP报文有效载荷中的所有有贡献的源。

#ifndef _rtp_header_h_

#define _rtp_header_h_

#include

/*

0 1 2 3

0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

|V=2|P|X| CC |M| PT | sequence number |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| timestamp |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

| synchronization source (SSRC) identifier |

+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+

| contributing source (CSRC) identifiers |

| .... |

+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+

*/

#define RTP_VERSION 2 // RTP version field must equal 2 (p66)

typedef struct _rtp_header_t

{

uint32_t v:2; /* protocol version */

uint32_t p:1; /* padding flag */

uint32_t x:1; /* header extension flag */

uint32_t cc:4; /* CSRC count */

uint32_t m:1; /* marker bit */

uint32_t pt:7; /* payload type */

uint32_t seq:16; /* sequence number */

uint32_t timestamp; /* timestamp */

uint32_t ssrc; /* synchronization source */

} rtp_header_t;

#define RTP_V(v) ((v >> 30) & 0x03) /* protocol version */

#define RTP_P(v) ((v >> 29) & 0x01) /* padding flag */

#define RTP_X(v) ((v >> 28) & 0x01) /* header extension flag */

#define RTP_CC(v) ((v >> 24) & 0x0F) /* CSRC count */

#define RTP_M(v) ((v >> 23) & 0x01) /* marker bit */

#define RTP_PT(v) ((v >> 16) & 0x7F) /* payload type */

#define RTP_SEQ(v) ((v >> 00) & 0xFFFF) /* sequence number */

#endif /* !_rtp_header_h_ */

H264

H264是一种由国际电信联盟和国际话组织联合开发的视频压缩标准,它旨在通过高效的压缩算法实现高质量视频的传输和存储,同时减低所诉的带宽和存储空间。

H264有两种组织格式

1. AVCC格式,MPEG-4格式,字节对齐,主要用于mp4/flv/mkv等封装中,AVCC格式使用NALU长度进行分割,在封装或者流的头部包含extradata信息,exteadata中含有NALU长度的字节数以及SPS和PPS信息。

2. Annex-B格式,MPEG-2 transport stream format格式,ts流中常用这种格式,本文也主要介绍这一种格式,Annex-B格式使用start code进行分割,start code有两种,一种为0x00 00 01,另一种0x00 00 00 01。

接收到SPS+PPS+SEI后表示这一帧为IDR帧。视频由frame组成,frame分为IDR帧、I帧、B帧、P帧,在推流H264视频时首先发送的就是一帧IDR帧,因为接收到IDR帧就得到了PPS和SPS,就可以知道视频的信息知道怎么解码,后面可以全是P帧,可以有B帧,可以有I帧,直播一般只有IDR帧、I帧和P帧。

NALU组成: [start code] [NAL头] [NAL payload]

看一下NAL头部的定义:

F : 1比特,一般为0。

NRI:2比特,指示NALU单元的重要性,一般不太关心。

TYPE:5比特,表示这个NALU单元的类型。

RTP三种封包模式

IP协议中MTU最大长度为1500字节:IP报头:20字节,UDP报头:8字节,RTP头12字节,NALU的长度不可以超过1460字节(RTP负载的NALU长度)。如果用TCP的话TCP报头20字节,自己算,就是一共不可以超过1500字节。

1. 单一封包模式:NALU可以放入一个RTP中不超过1500字节的可以使用这种模式,打包时除去start code即可,把其他的数据放入RTP包中即可。

2. 组合封包模式:当NALU长度很小,可以把几个NALU放入一个RTP包中且不超过1500字节的可以使用这种模式。常用的是STAP-A模式,这种模式同样去掉start code,然后在第一个NAL payload前加入 STAP-A头(1字节)紧接着是第一个NAL payload长度(2字节)然后紧接 NAL payload 。

RTP header + STAP-A头 + 第一个NAL payload长度 + 第二个NAL payload + 第二个NAL payload长度 + 第二个NAL payload ....

3. 分片封包模式:当NALU的长度超过了MTU时,使用分片的模式。在封装时需要使用FU indicator + FU header 替换NALU原来的头部。这种方式称为Fragmentation Units(FUs)。

FU indicator + FU header + FU payload ....

FU indicator:

F、NRI与NAL头相同含义,TYPE固定28。

FU Header

S:S = 1 表示分片打包的第一个包。

E:E = 1 表示分片打包的最后一个包。

TYPE:如果是H264的话就是NALU的TYPE。

FU payload 为去掉起始码和头部的NAL的NAL payload

RTP封装H264解析

RTP封装常用的就是单一封包和分片封包模式,组合基本不用。

RTP序号每发送一个包就 + 1 ,同一个NALU的分片的RTP包时间戳不变。

H264类型:

0没有定义1~23NAL单元 单个NAL单元包24STAP - A 单一时间的组合包25STAP - B 单一时间的组合包26MTAP16 多个时间的组合包27MTAP24 多个时间的组合包28FU - A 分片的单元29FU - B 分片的单元30~31没有定义解析时按照每一位去解析即可,最简单的解析方式使用wireshark去抓包一个字节一个去解析。