H.264编码分析--NALU,帧和GOP,视频序列

为什么要对视频编码?

视频编码是为了压缩视频。1个未压缩的1小时的1080p的视频(1秒25帧)占用大小:
1920x1080x4x3600x25=746,496,000,000字节,即700G左右
一部小电影这么大,我们的网络带宽和硬盘容量怎么承受的了。所以视频和图片这些大文件都是经过压缩的。
而H.264就是一种经典的视频编码(压缩)标准。

视频压缩原理

视频信息之所以存在大量可以被压缩的空间,是因为其中本身就存在大量的数据冗余。其主要类型有:
时间冗余:视频相邻的两帧之间内容相似,存在运动关系
空间冗余:视频的某一帧内部的相邻像素存在相似性
编码冗余:视频中不同数据出现的概率不同
视觉冗余:观众的视觉系统对视频中不同的部分敏感度不同

NALU

从存储结构的角度来讲,H.264是由一个个NALU(Network Abstraction Layer Unit–网络抽象层单元)组成的。
NALU可以看成由三部分组成:

  1. start_code
  2. NALU header
  3. RBSP(Raw Byte Sequence Payload–原始字节序列载荷)

image.png

start_code

起始码是三字节的0x000001或四字节的0x00000001,用来分割NALU单元。当读到start_code时,表示上一个NALU的结束,下一个NALU的开始。
为了避免后续的负载数据(RBSB)跟起始码冲突,H.264使用了emulation_prevention_three_byte。
emulation_prevention_three_byte 是一个等于 0x03 的字节。当一个 emulation_prevention_three_byte 出现在NAL 单元中时,应该被解码过程丢弃。
当原始数据是以下字节时会在第三字节处插入03,即
0x000000 -> 0x00000300
0x000001 -> 0x00000301
0x000002 -> 0x00000302
而解码的时候刚好相反,要去掉03

NALU header

头部占1个字节,包含三个字段。

image.png

forbidden_zero_bit

占1位,H.264规定为0

nal_ref_idc

占2位,表示该NALU的重要程度。SPS,PPS,IDR不应该为0,值越大越重要。

nal_unit_type

占5位,指定了RBSP的数据类型。主要关注1,5,6,7,8类型。
当header字节为:
0x41:非IDR帧,即P帧或B帧
0x65:IDR帧
0x67:SPS
0x68:PPS

RBSP

RBSP即Raw Byte Sequence Payload–原始字节序列负载。是SODB经过字节对齐后的字节流。
SODB–String Of Data Bits,指的是负载数据字节流。
当SODB最后一个字节使用不到8位时,先加1位1,后面填充0,这样就变成RBSP了。

SPS

nal_unit_type=7
SPS即Sequence parameter set–序列参集。
sequence parameter set 序列参数集:一个语法结构,包含应用于 0 个或多个完整编码视频序列的 语法元素,由条带头中的语法元素 pic_parameter_set_id 确定所引用的图像参数集,由图像参数集中的语法元素seq_parameter_set_id 确定所引用的序列参数集。
下图是某个.h264文件的SPS信息
image.png
SPS常用参数如下:
profile_idc 和 level_idc 是指比特流所遵守的配置和级别

profile_idc

profile_idc是一个表示编码器所采用的编码配置信息的参数。它的全称是"Profile Indication Parameter",意思是编码器所使用的视频编码配置文件的指示参数。在H.264标准中,定义了多个不同的profile_idc值,每个值对应着不同的视频编码配置信息,例如baseline、main、high等等。这些不同的配置信息可以影响视频的编码效率、图像质量和系统复杂度等方面。

level_idc

level_idc表示编码器所采用的编码级别。它的全称是"Level Indication Parameter",意思是编码器所使用的视频编码级别的指示参数。H.264标准中定义了多个不同的level_idc值,每个值对应着不同的视频编码级别,例如Level 1、Level 1.1、Level 1.2等等。这些不同的级别定义了视频编码所能达到的最大分辨率、最大帧率、最大比特率和最大缓冲区大小等参数,以及其他一些技术细节。编码器选择的level_idc值必须符合给定的profile_idc所支持的级别范围。

seq_parameter_set_id

seq_parameter_set_id 用于识别图像参数集所指的序列参数集。

max_num_ref_frames

指定了帧间预测的最大参考帧

pic_width_in_mbs_minus1

pic_width_in_mbs_minus1 加 1 是指以宏块为单元的每个解码图像的宽度。

pic_height_in_map_units_minus1

pic_height_in_map_units_minus1 加 1 表示以条带组映射为单位的一个解码帧或场的高度。

计算视频分辨率和帧率

num_units_in_tick和time_scale可用来计算帧率
https://www.jianshu.com/p/9d7e2a2629ee

PPS

nal_unit_type=8
picture parameter set 图像参数集:一个语法结构,包含应用于零个或多个编码图像的语法元素,由每个条带头部中的语法元素 pic_parameter_set_id 确定。
在视频编码标准H.264/AVC中,Picture Parameter Set(PPS)是一种视频参数集,用于描述视频序列中的一张图像的编码参数。PPS包含了一些图像特定的参数,如图像切片、参考帧选择、量化参数等。PPS被用来指示解码器如何解码视频序列中的每一张图像,以确保图像的正确性和一致性。PPS通常被编码为NAL单元,可以独立于其他视频参数集进行传输和存储。在解码过程中,解码器需要首先解码PPS,然后才能正确解码图像数据。
下图是某个.h264文件的PPS信息
image.png

IDR

nal_unit_type=5
IDR图像的编码切片
IDR图像和非IDR图像的slice语法结构相同,如下图:
image.png

非IDR

nal_unit_type=1
非IDR图像的编码切片

帧和GOP

I帧

I帧即帧内编码帧,又叫关键帧。(Intra-coded (I) frames/slices (key frames))
无需参考其他图像便可独立进行解码,视频序列中的第一个帧始终都是I帧。 它是⼀个全帧压缩编码帧。它将全帧图像信息进⾏JPEG压缩编码及传输。
I帧通常是每个GOP(MPEG所使用 的一种视频压缩技术)的第一个帧,经过适度地压缩,作为随机访问的参考点,可以当成静态图像。I帧可以看作一个图像经过压缩后的产物,I帧压缩可以得到6:1的压缩比而不会产生任何可觉察的模糊现象。I帧压缩可去掉视频的空间冗余信息,下面即将介绍的P帧和B帧是为了去掉时间冗余信息。

P帧

P帧即前向预测编码帧(Predicted § frames/slices),需要参考前面的一个I帧或P帧进行解码。
P帧和B帧都是帧间预测。P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据)

B帧

B帧即双向预测编码帧(Bi-directional predicted (B) frames/slices (macroblocks)),解码需要参考前面的一个I帧或P帧,和后面的一个I帧或P帧。
B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别,换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。
对实时性要求高的场景不使用B帧,例如直播,实时通话。

IDR帧

Instantaneous Decoding Refresh,即时解码刷新
是一种特殊的I帧。一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。

IDR帧和I帧的区别

All IDR frames are I-frames, but not all I-frames aare IDR frames. IDR (Instantaneous Decoder Refresh) frames are special I-frames that not only contain a complete picture, but also indicates that no P/B-frame after the IDR is allowed to reference a frame before the IDR.

GOP

GOP(group of pictures–图像组)是编码视频流中一组连续的图像。GOP用作形容两个I帧之间间隔多少帧,例如IBBPBBPBBPBBPBBI,GOP是15。
在H264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流。一个序列就是一段内容差异不太大的图像编码后生成的一串数据流。当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以编一个I帧,然后一直P帧、B帧了。当运动变化多时,可能一个序列就比较短了,比如就包含一个I帧和3、4个P帧。
在视频编码序列中,GOP即Group of picture(图像组),指两个I帧之间的距离,Reference(参考周期)指两个P帧之间的距离。两个I帧之间形成一组图片,就是GOP(Group Of Picture)。
image.png

帧的应用

视频监控系统中预览的视频画面是实时的,对画面的流畅性要求较高。采用I帧、P帧进行视频传输可以提高网络的适应能力,且能降低解码成本所以现阶段的视频解码都只采用I帧和P帧进行传输。海康摄像机编码,I帧间隔是50,含49个P帧。

视频序列的分区

编码视频序列(coded video sequence ): 访问单元序列,由按照解码顺序排列的 IDR 访问单元和紧随 其后的零个或多个非 IDR 访问单元组成,包括到下一个(不含)IDR 访问单元之前的所有访问单元。
编码视频序列在H.264标准中出现了很多次。

可以看到编码视频序列和GOP是有相似之处的。
视频序列可以看成是由连续的图像组成,也可以看成是多个GOP组成。
下图介绍了视频序列的划分

视频序列由连续的图像组成
1个图像即1帧

slice(条带/切片)

1个图像(picture)可以分成1个或多个slice(条带,切片)。通常1个编码图像对应1个slice。
slice在语法结构上分为header和data,data包括n个宏块。
image.png

Macroblocks(宏块)

image.png
视频解码最终会简化为从比特流中搜索和检索宏块,随后借助亮度和色度分量恢复像素颜色。

Subblock(子块)

H.264将图像分成一系列宏块和子块以进行压缩。以下是宏块和子块的简要说明:
宏块(Macroblock):宏块是H.264中的一个基本单元,它由一组16x16像素块组成。每个宏块可以包含一个完整的图像区域,包括YUV三个分量(亮度,蓝色色差和红色色差)。
子块(Subblock):子块是由宏块进一步分解的小块。H.264支持多种子块大小,包括4x4、8x8和16x16。子块的大小可以根据图像的复杂性进行调整,以便更好地压缩视频。
通过将图像分解为宏块和子块,H.264可以更好地利用视频中的空间相关性,并生成更高质量的压缩视频。

参考

  • T-REC-H.264-202108-I!!PDF-E.pdf

猜你喜欢

转载自blog.csdn.net/ET_Endeavoring/article/details/129812378