ZigZag Sin
登 陆
后面没有了 上一篇:*代码-提取 NALU 中第一个字节的信息

NALU 的常见问题汇总

乔红
2021-1-8 19:36 阅读 5220

NALU 的那些事

我们在上一小结中,阐述了 NALU 的第一个字节里面的内容。我们了解到在第一个字节内,低 5 位表示 nal_unit_type ,也就是 NALU 的类型,那么本节,我们就来详细看看这些类型

我们在这里再次列举一下 NALU 的类型有哪些:

nal_unit_typeNALU 类型
0未定义
1非 IDR SLICEslice_layer_without_partitioning_rbsp( )
2非 IDR SLICE,采用 A 类数据划分片段slice_data_partition_a_layer_rbsp( )
3非 IDR SLICE,采用 B 类数据划分片段slice_data_partition_b_layer_rbsp( )
4非 IDR SLICE,采用 C 类数据划分片段slice_data_partition_c_layer_rbsp( )
5IDR SLICEslice_layer_without_partitioning_rbsp( )
6补充增强信息 SEIsei_rbsp( )
7序列参数集 SPSseq_parameter_set_rbsp( )
8图像参数集 PPSpic_parameter_set_rbsp( )
9分隔符access_unit_delimiter_rbsp( )
10序列结束符end_of_seq_rbsp( )
11码流结束符end_of_stream_rbsp( )
12填充数据filler_data_rbsp( )
13序列参数扩展集seq_parameter_set_extension_rbsp( )
14~18保留
19未分割的辅助编码图像的编码条带slice_layer_without_partitioning_rbsp( )
20~23保留
24~31未指定

这些类型有的常用,有的并不是很常见。我们本次先来看看常见的。

常见到的 NALU 类型

我们可以先看一下我们上一小节写的样例程序,执行他,并观察一下输出结果。如下图:

注意图中用红线标出来的 nal_unit_type 的值。在这个视频文件中,我们发现前几个 NALU 的 type 分别是 7,8,6,5,1,1,1,1......

如果把他们形象得表示出来,那么他们应该是这样的:

NALU Type

其实这里出现的这五种类型,就是最常见到的五种类型。我们先来看 nalutype 等于 7 的时候。

nalutype = 7 SPS

通过查表,我们知道 nalutype 等于 7 的时候,这个 nalu 被称之为序列参数集,一般我们把它简称为 SPS。

nalutype = 8 PPS

当 nalutype 等于 8 的时候,这个 nalu 被称之为图像参数集,一般我们把它简称为 PPS。SPS 和 PPS 中存放了解码过程中所需要的各种参数,是 H.264 解码的前置条件,没有 SPS 和 PPS,视频将会无法解码,所以在解码的时候,我们总是首先把 SPS 和 PPS 传给解码器,供解码器初始化。我们会在后续章节中详细介绍 SPS 和 PPS。

nalutype = 5 IDR

当 nalutype 等于 5 的时候,这个 nalu 被称之为 IDR 帧,也叫做关键帧(确切的说,这里其实应该不叫做帧,应该叫做 slice,有的翻译把它叫做条带,大部分情况下,一个 slice 就是一帧,但是会存在例外的情况,这里不做过多纠结,之后的内容先管他叫做 Slice,在这里,Slice 和其他资料里的帧是相同的概念)。IDR Slice 一定是一个 I Slice,而 I Slice 却不一定是一个 IDR Slice。

提到 IDR Slice,将不得不提到与之关联的另外一个概念,GOP (Group of picture),从字面意思来看,GOP 就是指一组 Slice,但是在 GOP 的具体定义上,笔者发现了好多个版本的定义,这里列出一些常见的,供诸位参考。

  • 版本 1,出处不详,GOP 是从一个 I Slice 开始,直到碰到下一个 I Slice 结束,这个区间范围内的所有 Slice。这个版本显然是传播最广的,也是最容易理解的。
  • 版本 2,出自 x264,x264 对 GOP 进行了新的发明创造,创造除了 Open-GOP 和 Close-GOP 两种概念。
    • Open-GOP, Open-GOP 由一个 I Slice 开始,Open 是指这个 GOP 是开放的,在这个 GOP 中的 P Slice 和 B Slice 可以参考这个 GOP 开始的 I Slice 之前的 Slice。

      OPEN GOP

    • Close-GOP,Close-GOP 由一个 I Slice 开始,Close 是指这个 GOP 是封闭的,在这个 GOP 中的 P Slice 和 B Slice 不可以参考这个 GOP 开始的 I Slice 之前的 Slice。

      OPEN GOP

其实过度纠结 GOP 的定义并没有太多实际的意义,GOP 的概念其实也不是 H.264 标准的概念,而是在生产中,大家总结出来的一个方便理解的概念,对其进行过度解读,反而会造成不必要的误解。

而 IDR Slice 的一个关键特性在于,当解码器拿到一个 IDR 帧的时候,意味着解码进入了一个全新的阶段,之前缓存的解码信息可以清空掉,解码器相当于完全重置。这对于传输不稳定的流媒体来说至关重要,在一个 IDR 帧之后,上一个 GOP 里的错误不会蔓延到当前 GOP。这就是为什么 IDR 帧通常只在流媒体格式(RTMP,RTP)中被强调,而在类似 MP4 之类的储存格式中,因为不必担心丢包等,所以往往只有开头一个 IDR 帧。

nalutype = 1 SLICE

当 nalutype 等于 1 的时候,这个 nalu 被称之为 Slice,这里就是除了 IDR Slice 以外,其他的视频数据存放的地方了。其实,除了 IDR 的特殊属性之外,IDR Slice 和 普通的 Slice 在组成和解码原理上,几乎都是一模一样的。

nalutype = 6 SEI

当 nalutype 等于 6 的时候,这个 nalu 被称之为 SEI,也就是自定义信息,如果你想在码流中放入一些别的额外信息,就可以写到 SEI 信息里面。不过要注意的是,SEI 信息的重要性级别并不高,有些时候会在转码,转封装的过程中被忽略掉。

常见误区

  • 判断 nalutype,有很多资料上说,判断 NALU 的类型,直接看 NALU 的第一个字节,如果第一个字节是 0x67 ,则是 SPS,如果第一个字节是 0x68,则是 PPS。这显然是错误的,我们在上一小节(NALU 的第一个字节)中说过,NALU 的第一个字节包含 1 位的禁止位,2 位的重要性,剩下的 5 位,才是 nalutype。如果按照整个字节进行计算,虽然在大多数常见下是可以判断正确的(大部分场景下重要性都是相同的),但是无法覆盖全部案例。

  • 判断 I P B,很多资料里面写,如何判断一个 NALU 是不是 I Slice,只要判断其 nalutype 是否等于 5 就好了。这也是错误的,我们已经介绍过,IDR Slice 一定是一个 I Slice,而 I Slice 却不一定是一个 IDR Slice,那么即使这个 NALU 的 nalutype 等于 1,他也有可能是 I Slice。那么应该判断这个 Slice 是 I 还是 P 还是 B 呢?其实根据目前读到的数据来说,我们是判断不出来的,我们在后续章节中读取 Slice 的时候,再返回头来解决这个问题。

后面没有了 上一篇:*代码-提取 NALU 中第一个字节的信息
给我买个键盘吧。。。求打赏。。。
欢迎加群,一起交流~~~

643401840@qq.com

宝藏博客!!

2022-03-10 23:25:08

zekun@sina.cn

nalutype = 6 SEI 当 nalutype 等于 1 (此处笔误,应该是6)的时候,这个 nalu 被称之为 SEI,也就是自定义信息,如果你想在码流中放入一些别的额外信息,就可以写到 SEI 信息里面。不过要注意的是,SEI 信息的重要性级别并不高,有些时候会在转码,转封装的过程中被忽略掉。 ===>这里有个笔误。最后的误区说明,解决了我很久以来的疑问。谢谢,打赏!

2021-12-23 11:08:27

simp00@163.com

写的很好希望继续

2021-12-06 21:21:49

632212519@qq.com

博主大大,这里有个语病“在一个 IDR 帧之后,上一个 GOP 里的错误不会将不会蔓延到当前 GOP。”

2021-02-01 11:47:23