RTP包头还是贴一下吧,看起来方便:
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 |
| .... |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
这个就不多说了吧:)
接下来的就是H264的头了。
首先是NAL Unit Type,8个字节
+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+----------------------+
F: 定义为0
NRI(nal_ref_idc):00 不是用来构造I帧预测的参考帧。
非00 用来保持参考帧的完整性。
(什么东西啊,反正我是不明白,也用不到,下次去做编解码算了,看了N多概念,都不清楚,郁啊。)
Type(nal_unit_type): 如下表
Type | Packet Type | name
---------------------------------------------------------
0 | undefined -
1-23 | NAL unit | Single NAL unit packet
24 | STAP-A | Single-time aggregation packet
25 | STAP-B | Single-time aggregation packet
26 | MTAP16 | Multi-time aggregation packet
27 | MTAP24 | Multi-time aggregation packet
28 | FU-A | Fragmentation unit
29 | FU-B | Fragmentation unit
30-31| undefined -
说明一下:
H264 over RTP基本上分三种类型:
1. Single NAL unit packet 也就是实际的NAL类型,可以理解为一个包就是一帧H264数据,这个在实际中是比较多的。
2. Aggregation packet 一包数据中含有多个H264帧。还可以细分,下面讲。
3. Fragmentation unit 一帧数据被分为多个RTP包,这也是很常见的,特别是对于关键帧。
细分一下Aggregation packet:
Aggregation packet 可以分为四种:
STAP-A 包内的帧含有相同的NALU-Time,没有DON
STAP-B 包内的帧含有相同的NALU-Time,有DON
MTAP16 包内的帧含有不同的NALU-Time,timestamp offset = 16
MTAP24 包内的帧含有不同的NALU-Time,timestamp offset = 24
实际用到的比较多的是1-23,STAP-A(24)和FU-A(28)其他类型的没有碰到过,就没有去研究了,当然我指的是客户端。你要做发送端的话,你自己订吧。
从RTP得到的数据是没有NAL头的,关于NAL头在RFC3984和ITUTH264文档里的意义好像不太一样,当初就是这个混淆了,折腾了半天。具体的忘了,我也懒得再去找了,下次再看到时候补上。实际应用就是要加上个H264 STREAM 的头
h264_stream_head = 0x00,0x00,0x00,0x01 4字节
随后是NAL unit type ,这里指的是H264定义的NAL type,有点小差别,特别是在FU的时候,下面会讲。
Single NAL Unit Packet(1-23)
这个很简单了,一个包就是一帧数据。h264_stream_head + NAL_unit_type... 直接送去解码了。
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI| type | |
+-+-+-+-+-+-+-| |
| Bytes 2..n of a Single NAL unit |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
STAP-A(24)
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RTP Header |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|STAP-A NAL HDR| NALU 1 Size | NALU 1 HDR|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NALU 1 Data |
: :
+ +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| | NALU 2 Size | NALU 2 HDR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NALU 2 Data |
: :
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
看这个结构应该很清楚了,先是16位的长度,就可以得到地一帧,h264_stream_head + NALU 1 HDR...送去解码。再算下一帧。注意,不一定是32bit对齐的。
需要注意的这个NALU Size 是不包括他本身这2个字节。
FU-A(28)
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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator | FU header | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ |
| |
| FU payload |
| |
| +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| :... OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
FU Indicator
+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI| Type |
+----------------------+
FU Header
+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R| Type |
+----------------------+
S:1 表示是一帧的开始包
E:1 表示是一帧的结束包,和RTP marker位一致
R:0 必须
这里要注意一下,NAL unit type 必须自己拼装FU Indicator前四字节+ FU Header后四字节。也就是type字段是 FU header里的
nal_unit_type = (fu_indicator & 0xe0) | (fu_header & 0x1f)
等帧收齐了,加上H264_streaming_head + nal_unit_type....送去解码
有些已经记不清出了,都是从代码里推出来的,下次看的时候就该记下来。写的还真累啊,下班了,88