原文地址:H264 Over RTP 之 宝典
作者:zhanghongliusu
H264 Payload Format over RTP/RTCP,很久以前做的了,都快忘了,赶快复习一下吧,不然又还给...应该不是老师了吧,嘿嘿。
RTP包头还是贴一下吧,看起来方便:
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|V=2|P|X| CC
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| 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
|
+----------------------+
|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 -
0
1-23
24
25
26
27
28
29
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... 直接送去解码了。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|F|NRI| type
+-+-+-+-+-+-+-|
| Bytes 2..n of a Single NAL unit
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RTP Header
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|STAP-A NAL HDR| NALU 1 Size
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NALU 1 Data
: :
+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NALU 2 Data |
: :
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
看这个结构应该很清楚了,先是16位的长度,就可以得到地一帧,h264_stream_head + NALU 1 HDR...送去解码。再算下一帧。注意,不一定是32bit对齐的。
需要注意的这个NALU Size 是不包括他本身这2个字节。
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FU indicator
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
|
|
|
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
FU Indicator
+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|
Type |
+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|
+----------------------+
FU Header
+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R|
Type |
+----------------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R|
+----------------------+
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
参考资料:
1. RFC3984 -- RTP Payload Format for H.264 Video