一、H.264 的层次介绍
H.264 定义三个层次,每个层次支持一组特定的编码功能,并且依照各个层次指定所指定的功能。基础层次(baselineprofile)支持I
帧和 P 帧【1】的帧内和帧间编码,支持自适应的可变长度的熵编码(CAVLC)。主要层次(main profile)支持隔行扫描视频,B帧【2】的帧内编码,使用加权预测的帧内编码和使用上下文的算术编码(CABAV)。扩展层次(extendedprofile)不支持隔行扫描视频和CABAC,但增加了码流之间高效的转化模式(SP 和 SI 片)和增强了错误码的恢复能力(数据分割)。基础层次的潜在应用主要包括可视电话、视频会议和无线通讯;主要层次的应用在电视广播和视频存储;扩展层次主要应用在流媒体应用程序中。然而,每个文件有足够的灵活性,支持广泛的应用,这些应用的实例,不应被视为最终固定的。
二、H.264 的分层结构
H264 将其功能主要分为两层,即视频编码层(VCL)和网络提取层(NAL, Network Abstraction Layer)。VCL层负责编码,NAL层负责网络传输。
H.264 的视频提取层 NAL
H.264 的视频编码序列是由一系列的NAL 单元组成的。
我们知道00 00 00 01是NALU的开始标记
1. 网络抽象层单元类型 (NALU)
NALU 头由一个字节组成,
它的语法如下:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|Type |
+---------------+
F: 1 个比特(bit[q3] ).
forbidden_zero_bit.在 H.264
规范中规定了这一位必须为 0.
NRI:2 个比特. nal_ref_idc.
取 00 ~ 11,
似乎指示这个 NALU
的重要性,
如 00
的 NALU
解码器可以丢弃它而不影响图像的回放.
不过一般情况下不太关心这个属性.
Type:5 个比特.
nal_unit_type.这个 NALU
单元的类型.
简述如下:
0 没有定义
1-23NAL单元单个 NAL
单元包.
24STAP-A 单一时间的组合包
24STAP-B 单一时间的组合包
26MTAP16 多个时间的组合包
27MTAP24 多个时间的组合包
28FU-A 分片的单元
29FU-B 分片的单元
30-31没有定义
2. 打包模式rfc3550
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包头格式
前12个字节出现在每个RTP包中,仅仅在被混合器插入时,才出现CSRC识别符列表。这些域有以下意义:
版本(V):2比特 此域定义了RTP的版本。此协议定义的版本是2。(值1被RTP草案版本使用,值0用在最初"vat"语音工具使用的协议中。)
填充(P):1比特 若填料比特被设置,则此包包含一到多个附加在末端的填充比特,填充比特不算作负载的一部分。填充的最后一个字节指明可以忽略多少个填充比特。填充可能用于某些具有固定长度的加密算法,或者用于在底层数据单元中传输多个RTP包。
扩展(X):1比特 若设置扩展比特,固定头(仅)后面跟随一个头扩展。
CSRC计数(CC):4比特 CSRC计数包含了跟在固定头后面CSRC识别符的数目。
标志(M):1比特 标志的解释由具体协议规定。它用来允许在比特流中标记重要的事件,如帧边界。
负载类型(PT):7比特 此域定义了负载的格式,由具体应用决定其解释。协议可以规定负载类型码和负载格式之间一个默认的匹配。其他的负载类型码可以通过非RTP方法动态定义。RTP发送端在任意给定时间发出一个单独的RTP负载类型;此域不用来复用不同的媒体流。
序列号(sequence number):16比特 每发送一个RTP数据包,序列号加1,接收端可以据此检测丢包和重建包序列。序列号的初始值是随机的(不可预测),以使即便在源本身不加密时(有时包要通过翻译器,它会这样做),对加密算法泛知的普通文本攻击也会更加困难。
时间戳(timestamp) 32比特 时间戳反映了RTP数据包中第一个字节的采样时间。
SSRC:32比特 用以识别同步源。标识符应该被随机生成,以使在同一个RTP会话期中没有任何两个同步源有相同的SSRC识别符。
H.264 Payload 格式定义了三种不同的基本的负载(Payload)结构.
接收端可能通过 RTP Payload的第一个字节来识别它们.
这一个字节类似 NALU
头的格式,
而这个头结构的 NAL
单元类型字段则指出了代表的是哪一种结构,这个字节的结构如下,
可以看出它和 H.264
的 NALU
头结构是一样的.
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|Type |
+---------------+
字段 Type:
这个 RTP payload
中 NAL
单元的类型.
这个字段和 H.264
中类型字段的区别是,
当 type
的值为 24 ~ 31
表示这是一个特别格式的 NAL
单元,
而 H.264
中,
只取 1~23
是有效的值.
24STAP-A 单一时间的组合包
24STAP-B 单一时间的组合包
26MTAP16 多个时间的组合包
27MTAP24 多个时间的组合包
28FU-A 分片的单元
29FU-B 分片的单元
30-31没有定义
可能的结构类型分别有:
1. 单一 NAL
单元模式
即一个 RTP
包仅由一个完整的 NALU
组成.
这种情况下 RTP NAL
头类型字段和原始的 H.264的
NALU 头类型字段是一样的.
2. 组合封包模式
即可能是由多个 NAL
单元组成一个 RTP
包.
分别有4种组合方式: STAP-A, STAP-B, MTAP16, MTAP24.
那么这里的类型值分别是 24, 25, 26
以及 27.
3. 分片封包模式
用于把一个 NALU
单元封装成多个 RTP
包.
存在两种类型 FU-A
和 FU-B.
类型值分别是 28
和 29.
2.1 单一 NAL
单元模式(Single NAL Unit Packet:
一个RTP Payload
仅包含一个NAL
单元, NALU
类型号为1~23,
和H264
标准码流非常接近.)
对于 NALU
的长度小于 MTU
大小的包,
一般采用单一 NAL
单元模式.对于一个原始的 H.264 NALU
单元常由 [Start Code] [NALU Header][NALU Payload]
三部分组成,
其中 StartCode
用于标示这是一个NALU
单元的开始,
必须是 "00 00 00 01"
或"00 00 01", NALU
头仅一个字节,
其后都是 NALU
单元内容.
打包时去除 "00 00 01"
或"00 00 00 01"
的开始码,
把其他数据封包的 RTP
包即可.
0 1 23
0 1 23 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 |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
如有一个 H.264
的 NALU
是这样的:
[0000 00 01 67 42 A0 1E 23 56 0E 2F ... ]
这是一个序列参数集 NAL
单元. [00 00 00 01]
是四个字节的开始码, 67
是 NALU
头, 42
开始的数据是 NALU
内容.
封装成 RTP
包将如下:
[ RTPHeader ] [ 67 42 A0 1E 23 56 0E 2F ]
即只要去掉 4
个字节的开始码就可以了.
2.2 组合封包模式(Aggregation packet:
一个RTP Payload
包含多个NAL
单元.
有STAP-A, STAP-B, MTAP-A,MTAP-B
四种类型,
编号依次为 24, 25,26, 27.)
其次,
当 NALU
的长度特别小时,
可以把几个 NALU
单元封在一个 RTP
包中.
0 1 23
0 1 23 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| RTPHeader |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|STAP-ANAL HDR | NALU 1 Size | NALU 1 HDR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|NALU 1 Data |
: :
++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| |NALU 2 Size | NALU 2 HDR |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|NALU 2 Data |
: :
|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|:...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
2.3Fragmentation Units (FUs).(Fragmentation unit:
一个RTPPayload
包含一个NAL
单元的一部分.
有FU-A, FU-B
两种,分别标记为 28, 29.)
而当 NALU
的长度超过 MTU
时,
就必须对 NALU
单元进行分片封包.
也称为 Fragmentation Units (FUs).
0 1 23
0 1 23 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
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| FUindicator | FU header | |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+|
| |
| FUpayload |
| |
|+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|:...OPTIONAL RTP padding |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
Figure14. RTP payload format for FU-A
TheFU indicator octet has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|F|NRI|Type |
+---------------+
TheFU header has the following format:
+---------------+
|0|1|2|3|4|5|6|7|
+-+-+-+-+-+-+-+-+
|S|E|R|Type |
+---------------+
{
1,将FU-A包根据rtp的包序号和FU-A的header字节,组成完整264帧;
2,判断帧类型如果是idr帧,需要在帧头加上sps和pps,格式为:
起始码(0x00000001)+sps+起始码+pps+起始码+完整帧数据
3,帧末添加帧间分隔符“0x00, 0x00, 0x01, 0x09, 0x10”
4,使用网上精简过的"ff_264_dec_vc"进行解码。该项目不支持imgconvert,可从最新ff源码查找
并拷贝yuv420p_to_xxx函数进行合适转码
}
3. SDP 参数【3】
下面描述了如何在 SDP
中表示一个 H.264
流:
."m=" 行中的媒体名必须是 "video"
."a=rtpmap" 行中的编码名称必须是 "H264".
."a=rtpmap" 行中的时钟频率必须是 90000.
. 其他参数都包括在 "a=fmtp"
行中.
如:
m=video49170 RTP/AVP 98
a=rtpmap:98H264/90000
a=fmtp:98profile-level-id=42A01E; sprop-parameter-sets=Z0IACpZTBYmI,aMljiA==
下面介绍一些常用的参数.
3.1packetization-mode:表示支持的封包模式.
当 packetization-mode
的值为 0
时或不存在时,
必须使用单一 NALU
单元模式.
当 packetization-mode
的值为 1
时必须使用非交错(non-interleaved)封包模式.
当 packetization-mode
的值为 2
时必须使用交错(interleaved)封包模式.
这个参数不可以取其他的值.
3.2sprop-parameter-sets:
这个参数可以用于传输 H.264
的序列参数集和图像参数 NAL
单元.
这个参数的值采用 Base64
进行编码.
不同的参数集间用","号隔开.
3.3profile-level-id:
这个参数用于指示 H.264
流的 profile
类型和级别.
由 Base16(十六进制)
表示的 3
个字节.
第一个字节表示 H.264
的 Profile
类型,
第
三个字节表示 H.264
的 Profile
级别:
3.4max-mbps:
这个参数的值是一个整型,
指出了每一秒最大的宏块处理速度.
问题一:如何把h.264的包打包成rtp包?
答:打包时去除H.264的开始码,然后加上rtp头即可.
RTP打包H.264过程
1.打开.264文件
2.设置初始化套接字
3.从264码流中判断起始码,先读前3个字节,看是不是0x000001,如果不是的话,再多读取一个字节,看前4个字节是不是0x00000001。(读到156行)
【1】简单地说,I帧是关键帧,属于帧内压缩。就是和AVI的压缩是一样的。 P是向前搜索的意思。他们都是基于I帧来压缩数据。
I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)
P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,P帧没有完整画面数据,只有与前一帧的画面差别的数据)
【2】B是双向搜索,B帧记录的是本帧与前后帧的差别
【3】会话描述协议(SDP)为会话通知、会话邀请和其它形式的多媒体会话初始化等目的提供了多媒体会话描述。
这里是对网上资料自己的整理和自己加的东西,感谢网上各位的无私分享。
基于RTP的h.264视频传输系统设计(一),布布扣,bubuko.com