RTP
数据传输协议RTP,用于实时传输数据。
RTP数据发向偶数的UDP端口,而对应的控制信号RTCP数据发向相邻的奇数UDP端口(偶数的UDP端口+1),这样就构成一个UDP端口对。
RTP实际应用中的细节
- 发送端,上层应用程序以分组形式将编码后的媒体数据传给RTP通信模块,作为RTP报文的有效载荷,RTP通信模块将根据上层应用提供的参数在有效载荷前添加RTP报头,形成 RTP报文,通过Socket接口选择UDP协议发送出去。
接收端,RTP通信模块通过Socket接口接收到RTP报文后,将RTP报头分离出来作相应处理,再将RTP报文的有效载荷作为数据分组传递给上层应用。
RTP结构解析
RTP报文由两部分组成:报头和有效载荷
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 |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
根据RTP负载设置的RTP头信息
格式设置如下:
- Marker bit (M): 1 bit 如果是1,代表是访问单元的最后一个数据包
NTP
根据RTP规范,不同的RTP媒体流是分开传输的,且使用各自独立的时间戳进行同步。假设在一次视频点播中,传输两路RTP媒体流,一路视频,一路音频。根据视频帧时间戳,可以实现视频流内同步,这很好理解,通过视频帧时间戳可以计算出相邻视频帧的时间间隔,也就是视频帧之间的相对时间关系很容易通过时间戳来确定,按照这个间隔去呈现视频,就可以获得较好的效果。同理,音频流也可以实现自身的同步。
Session Description Protocol -- SDP
在会话前需要确定网络相关和媒体相关信息。sdp是文本型松散格式结构。偏向介绍WebRTC的SDP Offer/Answer 模型。
sdp对于发送方描述了想要什么类型接收者;接收者回应了想让发送者以什么格式发送。
RTP载荷H.264码流
H264的RTP中有三种不同的基本负载:
- Single NAL(单个NALU包模式),荷载中只包含一个NAL单元。NAL头类型域等于原始 NAL单元类型,即在范围1到23之间
- Aggregation Packet(组合包模式),本类型用于聚合多个NAL单元到单个RTP荷载中。本包有四种版本,单时间聚合包类型A (STAP-A),单时间聚合包类型B (STAP-B),多时间聚合包类型(MTAP)16位位移(MTAP16), 多时间聚合包类型(MTAP)24位位移(MTAP24)。赋予STAP-A, STAP-B, MTAP16, MTAP24的NAL单元类型号分别是 24,25, 26, 27
- Fragmentation Unit(分包模式),用于分片单个NAL单元到多个RTP包。现存两个版本FU-A,FU-B,用NAL单元类型 28,29标识。
常用的打包时的分包规则是:如果小于MTU采用单个NAL单元包,如果大于MTU就采用FUs分片方式。
因为常用的打包方式就是单个NAL包和FU-A方式,所以我们只解析这两种。
NAL
NAL单元由NAL头和NAL单元载荷组成。NAL单元分为两类:一类为参数集SPS,PPS NAL单元以及补充增强信息SEI NAL单元等。另一类为slice NAL单元。NAL单元载荷按8字节对齐。
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+---------------+
F: 1 bit, forbidden_zero_bit 在 H.264 规范中规定了这一位必须为 0.
NRI: 2 bit, nal_ref_idc, H.264规范要求nal_unit_type等于6、9、10、11或12的所有NAL单元的NRI值应为0。
Type: 4 bit, nal type
Payload Packet Single NAL Non-Interleaved Interleaved
Type Type Unit Mode Mode Mode
-------------------------------------------------------------
0 reserved ig ig ig
1-23 NAL unit yes yes no
24 STAP-A no yes no
25 STAP-B no no yes
26 MTAP16 no no yes
27 MTAP24 no no yes
28 FU-A no yes yes
29 FU-B no no yes
30-31 reserved ig ig ig
到这里应该都可以生成h.264的NAL单元。
JS实现RTP解析
var FIXED_HEADER_LENGTH = 12;
class RtpPacket {
constructor(buf) {
// Typed check
if (!buf instanceof Uint8Array) {
throw new Error("buf is not Uint8Array type");
}
if (buf.length < FIXED_HEADER_LENGTH) {
throw new Error("can not parse buffer smaller than fixed header");
}
let firstByte = buf.getUint8(0);
let secondByte = buf.getUint8(1);
// RTP协议的版本号
this.version = firstByte >>> 6;
// P(padbit):填充标志
this.padding = (firstByte >>> 5) & 1;
// X(extbit):扩展标志
this.has_extension = (firstByte >>> 4) & 1;
// CC:CSRC计数器
this.csrcCount = firstByte & 0x0f;
// M(markbit): 标记
this.marker = secondByte >>> 7;
// PT(paytype): 有效荷载类型
this.payloadType = secondByte & 0x7f;
// 序列号(seq_number):占16位
this.sequenceNumber = buf.getUint16(2);
// 时戳(timestamp)
this.timestamp = buf.getUint32(4);
// 同步信源(SSRC)标识符
this.ssrc = buf.getUint32(8);
// 特约信源(CSRC)标识符
this.csrc = [];
let byteIndex = FIXED_HEADER_LENGTH
this.payload = buf.slice(FIXED_HEADER_LENGTH + 4 * this.csrcCount);
}
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。