在 H.264/AVC 视频编码标准中,整个系统框架划分为如下两个层面:
因此平时每帧数据就是一个 NAL 单元。NAL 单元的实际格式如下:
.
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| NAL Header | EBSP | NAL Header | EBSP | ...
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
每个 NAL 单元都是由 1 字节 NAL header 和 若干整数字节的负荷数据 EBSP 构成。
在网络传输 H.264 数据时,一个 UDP 包就是一个 NALU,解码器可以很方便的检测出 NAL 分界和解码。但是如果编码数据存储为一个文件,原来的解码器将无法从数据流中分辨出每个 NAL 的起始位置和终止位置,因此 H.264 用起始码来解决这个问题。
H.264 编码中,在每个 NAL 前添加起始码 0x00000001(4bytes) 或 0x000001(3bytes),解码器在码流中检测到起始码,表明前一个 NAL 的结束并开始新的一个 NAL 单元。为了防止 NAL 内部出现 0x00000001 的数据,H.264 又提出 "防止竞争 emulation prevention" 机制,在编码完一个 NAL 时,如果检测出有连续的两个 0x00 字节,就在后面插入一个 0x03。当解码器再 NAL 内部检测到 0x000003 的数据时,就把 0x03 抛弃,恢复原始数据。
NAL Header 的格式如下所示:
.
0 1 2 3 4 5 6 7
+-+-+-+-+-+-+-+-+
|F|NRI| TYPE |
+-+-+-+-+-+-+-+-+
TYPE 的取值如下表所示:
H.264 的具体封装过程如下:
VCL 层输出的比特流 SODB(String Of Data Bits)到 nal_unit 之间,经过以下三步处理:
SODB 字节对齐处理后封装成 RBSP(Raw Byte Sequence Payload)。
为防止 RBSP 的字节流与有序字节流传送方式下的 SCP (start_code_prefix_one_3bytes,0x000001)出现字节竞争情形,循环检测 RBSP 前三个字节,在出现字节竞争时在第三个字节前加入 emulation_prevention_three_byte(0x03),具体如下:
nal_unit(NumBytesInNALunit)
{
forbidden_zero_bit;
nal_ref_idc;
nal_unit_type;
NumBytesInRBSP = 0;
for (i = 1; i < NumBytesInNALunit; i++)
{
if (i + 2 < NumBytesInNALunit && next_bits(24) == 0x000003)
{
rbsp_byte[ NumBytesInRBSP++ ];
rbsp_byte[ NumBytesInRBSP++ ];
i += 2;
emulation_prevention_three_byte; /* equal to 0x03 */
}
else
{
rbsp_byte[ NumBytesInRBSP++ ]
}
}
}
防止字节竞争处理后的 RBSP(即此时为 EBSP 了)再加上一个字节的 NAL Header(forbidden_zero_bit + nal_ref_idc + nal_unit_type),封装成 nal_unit。
byte_stream_nal_unit( NumBytesInNALunit )
{
while( next_bits( 24 ) != 0x000001 )
zero_byte /* equal to 0x00 */
if( more_data_in_byte_stream( ) )
{
start_code_prefix_one_3bytes /* equal to 0x000001 */ nal_unit( NumBytesInNALunit )
}
}
类似H.320和MPEG-2/H.222.0等传输系统,传输NAL作为有序连续字节或比特流,同时要依靠数据本身识别NAL单元边界。在这样的应用系统中,H.264/AVC规范定义了字节流格式,每个NAL单元前面增加3个字节的前缀,即同步字节。在比特流应用中,每个图像需要增加一个附加字节作为边界定位。还有一种可选特性,在字节流中增加附加数据,用做扩充发送数据量,能实现快速边界定位,恢复同步.
分组打包的规则:
RTP 的头标可以是 NALU 的头标,并可以实现以上的打包规则。
一个 RTP 分组里放入一个 NALU,将 NALU(包括同时作为载荷头标的 NALU 头)放入 RTP 载荷中,设置 RTP 头标值。为了避免 IP 层对大分组的再一次分割,片分组的大小一般都要小于 MTU 尺寸。由于包传送的路径不同,解码端要重新对片分组排序,RTP 包含的次序信息可以用来解决这一问题。
对于预先已经编码的内容,NALU 可能大于 MTU 尺寸的限制。虽然 IP 层的分割可以使数据块小于 64k 字节,但无法在应用层实现保护,从而降低了非等重保护方案的效果。由于 UDP 数据包小于 64k 字节,而且一个片的长度对某些应用场合来说太小,所以应用层打包是 RTP 打包方案的一部分。
新的讨论方案(IETF)应当符合以下特征:
一些 NALU 如 SEI 、参数集等非常小,将他们合并在一起有利于减少头标开销。已有两种集合分组:
NAL 规范视频数据的格式,主要是提供头部信息,以适合各种媒体的传输和存储。NAL支持各种网络,包括:
NAL 规定一种通用的格式,既适合面向包传输,也适合流传送。实际上,包传输和流传输的方式是相同的,不同之处是传输前面增加了一个起始码前缀在类似 Internet/RTP 面向包传送协议系统中,包结构中包含包边界识别字节,在这种情况下,不需要同步字节。
NAL 单元分为 VCL 和 非VCL 两种:
参数集是很少变化的信息,用于大量 VCL NAL 单元的解码,分为两种类型:
序列和图像参数集机制,减少了重复参数的传送,每个 VCL NAL 单元包含一个标识,指向有关的图像参数集,每个图像参数集包含一个标识,指向有关的序列参数集的内容。因此,只用少数的指针信息,应用大量的参数,大大减少每个 VCL NAL 单元重复传送的信息。
序列和图像参数集可以在发送 VCL NAL 单元以前发送,并且重复传送,大大提高纠错能力。序列和图像参数集可以在"带内",也可以用更为可靠的其他"带外" 通道传送。
视频压缩中,每一帧代表一副静止的图像。而在实际压缩时,会采取各种算法减少数据的容量,其中 IPB 就是最常见的。
简单地说,I帧 就是关键帧,属于帧内压缩。P 是向前搜索的意思。B 是双向搜索。它们都是基于 I帧 来压缩数据。
采用的压缩方法:分组,将几帧图像分为一组(GOP),为防止运动变化,帧数不宜取多。
I 图像(帧)是靠尽可能去除图像空间冗余信息来压缩传输数据量的帧内编码图像。
I帧 又称为内部画面(intra picture),I帧 通常是每个 GOP(MPEG 所使用的一种视频压缩技术)的第一个帧,经过适度地压缩(作为随机访问的参考点)可以当成是图像。在 MPEG 编码的过程中部分视频帧序列压缩成为 I帧,部分压缩成 P帧,还有部分压缩成 B帧。I帧 法是帧内压缩法(P、B 为帧间),也称为"关键帧"压缩法。I帧 法是基于离散余弦变换 DCT(Discrete Cosine Transform)的压缩技术,这种算法与 JPEG 压缩算法类似。采用I帧压缩可达到 1/6 的压缩比而无明显的压缩痕迹。
P图像(帧)是通过充分降低图像序列中前面已编码帧的时间冗余信息来压缩传输数据量的编码图像,也叫预测帧。
在针对连续动态图像编码时,将连续若干幅图像分成 P,B,I 三种类型,P帧 由在它前面的 P帧 或 I帧 预测而来,它比较与它前面的 P帧 或 I帧 之间的相同信息或数据,也即考虑运动的特性进行帧间压缩。P帧 法是根据本帧与相邻的前一帧(I帧 或 P帧)的不同点来压缩本帧数据。采取 P帧 和 I帧 联合压缩的方法可达到更高的压缩且无明显的压缩痕迹。
P 帧是以 I 帧为参考帧,在 I 帧中找出 P 帧"某点"的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端根据运动矢量从 I 帧中找出 P 帧"某点"的预测值并与差值相加以得到 P 帧"某点"样值,从而得到完整的 P 帧。
B 图像(帧)是既考虑与源图像序列前面已编码帧,也顾及源图像序列后面已编码帧之间的时间冗余信息来压缩传输数据量的编码图像,也叫双向预测帧。
B 帧法是双向预测的帧间压缩法。当把一帧图像压缩成 B 帧时,它根据相邻的前一帧、本帧以及后一帧数据的不同点来压缩本帧,也即仅记录本帧与前后帧的差值。只有采用 B 帧压缩才能达到 200:1 的高压缩。一般地,I 帧压缩效率最低,P 帧较高,B 帧最高。
B 帧以前面的 I 帧或 P 帧以及后面的 P 帧为参考帧,"找出" B 帧 "某点" 的预测值和两个运动矢量,并取预测值和运动矢量传送。接收端根据运动矢量在两个参考帧中 "找出(算出)" 预测值并与差值求和,得到 B 帧 "某点" 样值,从而得到完整的 B 帧。
在没有 B 帧的情况下 dts 的顺序和 pts 的顺序是一样的。
dts 主要用于视频的解码,在解码阶段使用。pts 主要用于视频的同步和输出,在 display 的时候使用。在没有 B frame 的情况下,dts 和 pts 的输出顺序是一样的。
下面给出一个 GOP 为 15 的例子,其解码的参照 frame 及其解码的顺序都在里面:
如上图,I 帧的解码不依赖于任何的其它的帧,而 P 帧的解码则依赖于前面的 I 帧或者 P 帧。B 帧的解码则依赖于其前的最近的一个 I 帧或者 P 帧及其后的最近的一个 P 帧。
TaigaComplex 写的 h.264语法结构分析。
手机扫一扫
移动阅读更方便
你可能感兴趣的文章