searchusermenu
  • 发布文章
  • 消息中心
点赞
收藏
评论
分享

音视频 H264 编解码协议(概念、码流分层结构、NALU Header & RBSP)

2024-07-17 09:39:48
60
0

1、概述

H264是MPEG-4标准所定义的最新编码格式,同时也是技术含量最高、代表最新技术水平的视频编码格式之一,标准写法应该是H.264。H.264视频格式是经过有损压缩的,但是在技术上尽可能做到降低存储体积下获得较好图象质量和低带宽图像快速传输。

2、相关概念

下图为H.264码流分层

2.1 VCL&NAL

H264 原始码流是由一个接一个 NALU(NAL Unit) 组成,它的功能分为两层,VCL(Video Coding Layer)视频编码层和 NAL(Network Abstraction Layer)网络提取层。

  • VCL:包括核心压缩引擎和块、宏块和片的语法级别定义,设计目标是尽可能地独立于网络进行高效的编码;
  • NAL:负责将 VCL 产生的比特字符串适配到各种各样的网络和多元环境中,覆盖了所有片级以上的语法级别;

NAL是 H.264 为适应网络传输应用而制定的一层数据打包操作。传统的视频编码算法编完的视频码流在任何应用领域下(无论用于存储、传输等)都是统一的码流模式,视频码流仅有视频编码层 VCL(Video Coding Layer)。而 H.264 可根据不同应用增加不同的 NAL 片头,以适应不同的网络应用环境,减少码流的传输差错。

在 VCL 进行数据传输或存储之前,这些编码的 VCL 数据,被映射或封装进NAL单元(NALU)。

一个 NALU = 一组对应于视频编码的 NALU 头部信息 + 一个原始字节序列负荷(RBSP,Raw Byte Sequence Payload)

一个原始的 H.264 NALU 单元常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成,其中 Start Code 用于标示这是一个NALU 单元的开始,必须是 “00 00 00 01”

实际原始视频图像数据保存在 VCL 分层的 NAL Units 中

2.2 片(slice)

片是 H.264 提出的新概念,实际原始视频图像数据保存在 VCL 层级的 NAL Unit 中,这部分数据在码流中被称作是片(slice)。一个 slice 包含一帧图像的部分或全部数据,换言之,一帧视频图像可以编码为一个或若干个 slice。一个 slice 最少包含一个宏块,最多包含整帧图像的数据。在不同的编码实现中,同一帧图像中所构成的 slice 数目不一定相同。

一个 slice 编码之后被打包进一个 NALU,所以 slice = NALU

那么为什么要设置片呢?

设置片的目的是为了限制误码的扩散和传输,应使编码片相互间是独立的。某片的预测不能以其他片中的宏块为参考图像,这样某一片中的预测误差不会传播到其他片中。

在上图中,可以看到每个图像中,若干宏块(Macroblock)被排列成片。一个视频图像可编成一个或更多个片,每片包含整数个宏块(MB),每片至少包含一个宏块。

slice类型

slice 组成

每一个 slice 总体来看都由两部分组成,一部分作为 slice header,用于保存 slice 的总体信息(如当前 slice 的类型等),另一部分为 slice body,通常是一组连续的宏块结构(或者宏块跳过信息)

2.3 宏块(Macroblock)

刚才在片中提到了宏块,那么什么是宏块呢?

宏块是视频信息的主要承载者。一个编码图像通常划分为多个宏块组成.包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中像素阵列。

一个宏块由一个 16×16 亮度像素和附加的一个 8×8 Cb 和一个 8×8 Cr 彩色像素块组成。

2.4 帧(frame)和场(filed)

视频的一场和一帧用来产生一个编码图像,一帧通常是一个完整的图像,当采集视频信号时,如果采用隔行扫描(奇、偶数行),则扫描下来的一帧图像就被分成了两个部分,这每一部分都被称为 [场],根据次序,分为 [顶场] 和 [底场]。

为什么会产生场的概念?

人眼可察觉到的电视视频图像刷新中的闪烁为 0.02 秒,即当电视系统的帧率低于 50 帧/秒,人眼可感觉得出画面的闪烁。常规如 PAL 制式电视系统帧率为 25 帧/秒、NTSC 制式的则为 30 帧/秒,如果采用逐行扫描将不可避免地在视频刷新时产生闪烁现象。而另一方面如果单纯的提高帧率达到避免闪烁刷新效果,则会增加系统的频带宽度。

这便引出了隔行扫描技术及 [场] 的概念

在隔行扫描中,每一帧包含两个场(top field)和(bottom field),其中每个 field 包含一帧中一半数量的水平线,top field 包含所有奇数线,bottom field 则包含所有偶数线。则在电视显示过程中,电子枪每发射一行隔一行—先发射奇数行13579…(top field)回头再发射2468…(bottom field)利用两次扫描来完成一幅图像,因为视觉的滞留性,我们看到的效果是差不多的。如在 NTSC 视频中 frame 的频率为30次/秒而field的频率则为 60 次/秒,大于了人眼可察觉闪烁的频率。

适用类型

2.5 I 帧、P 帧、B 帧与 pts/dts

  • I frame: 自身可以通过视频解压算法解压成一张单独的完整的图片;
  • P frame:需要参考其前面的一个 I frame 或者 B frame 来生成一张完整的图片;
  • B frame: 则要参考其前一个 I 或者 P帧 及其后面的一个 P 帧来生成一张完整的图片;

pts/dts

DTS 与 PTS 的不同:
DTS 主要用户视频的解码,在解码阶段使用。PTS主要用于视频的同步和输出,在 display 的时候使用。再没有 B frame 的时候输出顺序是一样的。

2.6 GOP

GOP 是画面组,一个 GOP 是一组连续的画面。
GOP 一般有两个数字,如 M = 3,N = 12,M 制定 I 帧与 P 帧之间的距离,N 指定两个 I 帧之间的距离。那么现在的 GOP 结构是

I BBP BBP BBP BB I

增大图片组能有效的减少编码后的视频体积,但是也会降低视频质量,至于怎么取舍,得看需求了。

2.7 IDR

一个序列的第一帧叫做 IDR帧(Instantaneous Decoding Refresh,立即解码刷新)。

I 帧和 IDR 帧都是使用帧内预测,本质上是同一个东西,在解码和编码中为了方便,将视频序列中第一个 I 帧和其他 I 帧区分开,所以把第一个 I 帧称作 IDR,这样就方便控制编码和解码流程。

IDR 帧的作用是立刻刷新,使错误不致传播,从 IDR 帧开始,重新算一个新的序列开始编码。

核心作用

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

3、H264 码流分层结构

如上图,在 H264 中,句法元素共被组织成:序列、图像(帧)、片、宏块、子宏块五个层次。

句法元素的分层结构有助于更有效地节省码流。例如,在一个图像中,经常会在各个片之间有相同的数据,如果每个片都同时携带这些数据,势必会造成码流的浪费。更为有效的做法是将该图像的公共信息抽取出来,形成图像一级的句法元素,而在片级只携带该片自身独有的句法元素。

4、NALU Header & RBSP 结构

如上图:NALU = NAL Header + RBSP

4.1 NALU Header

前面已经说到,每个 NALU 由一个字节的 Header 和 RBSP(Raw Byte Sequence Payload) 组成。

NALU Header 由三部分组成,forbidden_bit(1bit),nal_ref_idc(2bits)代表优先级,nal_unit_type(5bits)代表该 NALU 的类型。

forbidden_zero_bit

1 bit,H264 规定此位必须为 0

nal_ref_idc

用于表示当前 NALU 的重要性,值越大,越重要。

解码器在解码处理不过来的时候,可以丢掉重要性为 0 的 NALU。

  • nal_ref_idc 不等于 0 时, NAL unit 的内容可能是 SPS/PPS/参考帧 的片
  • nal_ref_idc 等于 0 时,NAL unit 的内容可能是非参考图像的片
  • 当某个图像的片的 nal_ref_id 等于 0 时,该图像的所有片均应等于 0

nal_unit_type

nal_unit_type 是否包含 VCL 层编码数据分为 VCL NAL units 和 non-VCL NAL units;
VCL NAL units 中包含 VCL 层编码输出的数据, 而 non-VCL NAL units 则不包含。

所有的值对于类型如下:

4.2 RBSP

上图是 RBSP 序列举例

上图是 RBSP 的描述

SODB 与 RBSP

SODB 数据比特串 -> 是编码后的原始数据.
RBSP 原始字节序列载荷 -> 在原始编码数据的后面添加了 结尾比特。一个 bit “1” 若干比特 “0”,以便字节对齐。

 

0条评论
作者已关闭评论
李****建
6文章数
1粉丝数
李****建
6 文章 | 1 粉丝

音视频 H264 编解码协议(概念、码流分层结构、NALU Header & RBSP)

2024-07-17 09:39:48
60
0

1、概述

H264是MPEG-4标准所定义的最新编码格式,同时也是技术含量最高、代表最新技术水平的视频编码格式之一,标准写法应该是H.264。H.264视频格式是经过有损压缩的,但是在技术上尽可能做到降低存储体积下获得较好图象质量和低带宽图像快速传输。

2、相关概念

下图为H.264码流分层

2.1 VCL&NAL

H264 原始码流是由一个接一个 NALU(NAL Unit) 组成,它的功能分为两层,VCL(Video Coding Layer)视频编码层和 NAL(Network Abstraction Layer)网络提取层。

  • VCL:包括核心压缩引擎和块、宏块和片的语法级别定义,设计目标是尽可能地独立于网络进行高效的编码;
  • NAL:负责将 VCL 产生的比特字符串适配到各种各样的网络和多元环境中,覆盖了所有片级以上的语法级别;

NAL是 H.264 为适应网络传输应用而制定的一层数据打包操作。传统的视频编码算法编完的视频码流在任何应用领域下(无论用于存储、传输等)都是统一的码流模式,视频码流仅有视频编码层 VCL(Video Coding Layer)。而 H.264 可根据不同应用增加不同的 NAL 片头,以适应不同的网络应用环境,减少码流的传输差错。

在 VCL 进行数据传输或存储之前,这些编码的 VCL 数据,被映射或封装进NAL单元(NALU)。

一个 NALU = 一组对应于视频编码的 NALU 头部信息 + 一个原始字节序列负荷(RBSP,Raw Byte Sequence Payload)

一个原始的 H.264 NALU 单元常由 [StartCode] [NALU Header] [NALU Payload] 三部分组成,其中 Start Code 用于标示这是一个NALU 单元的开始,必须是 “00 00 00 01”

实际原始视频图像数据保存在 VCL 分层的 NAL Units 中

2.2 片(slice)

片是 H.264 提出的新概念,实际原始视频图像数据保存在 VCL 层级的 NAL Unit 中,这部分数据在码流中被称作是片(slice)。一个 slice 包含一帧图像的部分或全部数据,换言之,一帧视频图像可以编码为一个或若干个 slice。一个 slice 最少包含一个宏块,最多包含整帧图像的数据。在不同的编码实现中,同一帧图像中所构成的 slice 数目不一定相同。

一个 slice 编码之后被打包进一个 NALU,所以 slice = NALU

那么为什么要设置片呢?

设置片的目的是为了限制误码的扩散和传输,应使编码片相互间是独立的。某片的预测不能以其他片中的宏块为参考图像,这样某一片中的预测误差不会传播到其他片中。

在上图中,可以看到每个图像中,若干宏块(Macroblock)被排列成片。一个视频图像可编成一个或更多个片,每片包含整数个宏块(MB),每片至少包含一个宏块。

slice类型

slice 组成

每一个 slice 总体来看都由两部分组成,一部分作为 slice header,用于保存 slice 的总体信息(如当前 slice 的类型等),另一部分为 slice body,通常是一组连续的宏块结构(或者宏块跳过信息)

2.3 宏块(Macroblock)

刚才在片中提到了宏块,那么什么是宏块呢?

宏块是视频信息的主要承载者。一个编码图像通常划分为多个宏块组成.包含着每一个像素的亮度和色度信息。视频解码最主要的工作则是提供高效的方式从码流中获得宏块中像素阵列。

一个宏块由一个 16×16 亮度像素和附加的一个 8×8 Cb 和一个 8×8 Cr 彩色像素块组成。

2.4 帧(frame)和场(filed)

视频的一场和一帧用来产生一个编码图像,一帧通常是一个完整的图像,当采集视频信号时,如果采用隔行扫描(奇、偶数行),则扫描下来的一帧图像就被分成了两个部分,这每一部分都被称为 [场],根据次序,分为 [顶场] 和 [底场]。

为什么会产生场的概念?

人眼可察觉到的电视视频图像刷新中的闪烁为 0.02 秒,即当电视系统的帧率低于 50 帧/秒,人眼可感觉得出画面的闪烁。常规如 PAL 制式电视系统帧率为 25 帧/秒、NTSC 制式的则为 30 帧/秒,如果采用逐行扫描将不可避免地在视频刷新时产生闪烁现象。而另一方面如果单纯的提高帧率达到避免闪烁刷新效果,则会增加系统的频带宽度。

这便引出了隔行扫描技术及 [场] 的概念

在隔行扫描中,每一帧包含两个场(top field)和(bottom field),其中每个 field 包含一帧中一半数量的水平线,top field 包含所有奇数线,bottom field 则包含所有偶数线。则在电视显示过程中,电子枪每发射一行隔一行—先发射奇数行13579…(top field)回头再发射2468…(bottom field)利用两次扫描来完成一幅图像,因为视觉的滞留性,我们看到的效果是差不多的。如在 NTSC 视频中 frame 的频率为30次/秒而field的频率则为 60 次/秒,大于了人眼可察觉闪烁的频率。

适用类型

2.5 I 帧、P 帧、B 帧与 pts/dts

  • I frame: 自身可以通过视频解压算法解压成一张单独的完整的图片;
  • P frame:需要参考其前面的一个 I frame 或者 B frame 来生成一张完整的图片;
  • B frame: 则要参考其前一个 I 或者 P帧 及其后面的一个 P 帧来生成一张完整的图片;

pts/dts

DTS 与 PTS 的不同:
DTS 主要用户视频的解码,在解码阶段使用。PTS主要用于视频的同步和输出,在 display 的时候使用。再没有 B frame 的时候输出顺序是一样的。

2.6 GOP

GOP 是画面组,一个 GOP 是一组连续的画面。
GOP 一般有两个数字,如 M = 3,N = 12,M 制定 I 帧与 P 帧之间的距离,N 指定两个 I 帧之间的距离。那么现在的 GOP 结构是

I BBP BBP BBP BB I

增大图片组能有效的减少编码后的视频体积,但是也会降低视频质量,至于怎么取舍,得看需求了。

2.7 IDR

一个序列的第一帧叫做 IDR帧(Instantaneous Decoding Refresh,立即解码刷新)。

I 帧和 IDR 帧都是使用帧内预测,本质上是同一个东西,在解码和编码中为了方便,将视频序列中第一个 I 帧和其他 I 帧区分开,所以把第一个 I 帧称作 IDR,这样就方便控制编码和解码流程。

IDR 帧的作用是立刻刷新,使错误不致传播,从 IDR 帧开始,重新算一个新的序列开始编码。

核心作用

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

3、H264 码流分层结构

如上图,在 H264 中,句法元素共被组织成:序列、图像(帧)、片、宏块、子宏块五个层次。

句法元素的分层结构有助于更有效地节省码流。例如,在一个图像中,经常会在各个片之间有相同的数据,如果每个片都同时携带这些数据,势必会造成码流的浪费。更为有效的做法是将该图像的公共信息抽取出来,形成图像一级的句法元素,而在片级只携带该片自身独有的句法元素。

4、NALU Header & RBSP 结构

如上图:NALU = NAL Header + RBSP

4.1 NALU Header

前面已经说到,每个 NALU 由一个字节的 Header 和 RBSP(Raw Byte Sequence Payload) 组成。

NALU Header 由三部分组成,forbidden_bit(1bit),nal_ref_idc(2bits)代表优先级,nal_unit_type(5bits)代表该 NALU 的类型。

forbidden_zero_bit

1 bit,H264 规定此位必须为 0

nal_ref_idc

用于表示当前 NALU 的重要性,值越大,越重要。

解码器在解码处理不过来的时候,可以丢掉重要性为 0 的 NALU。

  • nal_ref_idc 不等于 0 时, NAL unit 的内容可能是 SPS/PPS/参考帧 的片
  • nal_ref_idc 等于 0 时,NAL unit 的内容可能是非参考图像的片
  • 当某个图像的片的 nal_ref_id 等于 0 时,该图像的所有片均应等于 0

nal_unit_type

nal_unit_type 是否包含 VCL 层编码数据分为 VCL NAL units 和 non-VCL NAL units;
VCL NAL units 中包含 VCL 层编码输出的数据, 而 non-VCL NAL units 则不包含。

所有的值对于类型如下:

4.2 RBSP

上图是 RBSP 序列举例

上图是 RBSP 的描述

SODB 与 RBSP

SODB 数据比特串 -> 是编码后的原始数据.
RBSP 原始字节序列载荷 -> 在原始编码数据的后面添加了 结尾比特。一个 bit “1” 若干比特 “0”,以便字节对齐。

 

文章来自个人专栏
直播音视频编码
4 文章 | 1 订阅
0条评论
作者已关闭评论
作者已关闭评论
0
0