H.264码流中没有音频、没有时间戳、除了图像本身信息啥都没有。(没有时间戳,不能正常播放)

mp4 mkv 这些容器加时间戳。

1 基本概念

  • NALU:Network Abstraction Layer Unit 网络抽象层单元。NALU将编码后的视频数据分割成多个单元,每个单元可以单独处理和传输。

  • VCL(VideoCoding Layer,视频编码层):负责高效的视频内容表示。(指的不是编码数据的一帧,是描述视频数据的一层)

  • NAL(NetWorkAbstraction Layer,网络提取层):负责以网络所要求的恰当方式对数据进行打包和发送。

  • SODB(String of Data Bits,数据比特串):最原始的编码数据,即VCL数据,没有任何附加数据。

  • RBSP(Raw Byte Sequence Payload,原始字节序列载荷):在SODB的后面填加了结尾比特(RBSP trailing bits),一个bit“1”(表示结尾),若干bit “0”(填充),以便字节对齐;

  • EBSP (Encapsulation Byte Sequence Packets,扩展字节序列载荷):在RBSP基础上填加了仿校验字节(0X03)。它的原因是:在NALU加到Annexb上时,需要添加每组NALU之前的开始码StartCodePrefix,如果该NALU对应的slice为一帧的开始则用4位字节表示,ox00000001,否则用3位字节表示ox000001(是一帧的一部分)。解码器检测每个起始码,作为一个NAL的起始标识,当检测到下一个起始码时,当前NAL结束。对于NAL中数据出现0x000001或0x000000时,H.264引入了防止竞争机制,如果编码器遇到两个字节连续为0,就插入一个字节的0x03。解码时将0x03去掉,也称为脱壳操作。

  • SPS(Sequence Parameter Sets,序列参数集):对应的是针对一段连续编码视频序列的参数。包含帧数、POC的约束、参考帧数目、解码图像的尺寸(长宽)和帧场编码模式选择标识等信息。

  • PPS(Picture Parameter Set,图像参数集):作用于编码视频序列中一个或多个独立的图像。

  • SEI(Supplemental enhancement information,附加增强信息):包含了视频画面定时等信息,一般放在主编码图像数据之前,在某些应用中,它可以被省略掉。

  • IDR(Instantaneous Decoding Refresh,即时解码刷新):

  • HRD(Hypothetical Reference Decoder,假想码流调度器):

1.1 NALU单元

alt text

SPS,PPS,IDR都是NALU单元,只不过是不同类型。

1.1 序列参数集SPS

SPS(Sequence Parameter Set,序列参数集)是一个关键的结构,用于存储一系列编码器的设置,这些设置在整个视频序列(或多个序列)中是恒定的。SPS包含了描述视频序列特性的信息,对于解码器正确解码视频至关重要。以下是SPS的主要作用:

  1. 图像尺寸(宽度和高度)

  2. 帧速率

  3. 指定了编码器所使用的Profile(如Baseline、Main、High等)和Level(如1.0, 2.1, 4.0等)。这些参数定义了编码器支持的功能和限制(如最大分辨率、最大比特率等)。

  4. 最大参考帧数量、宏块尺寸等。

1.2 图像参数集PPS

PPS(Picture Parameter Set,图像参数集)是与SPS(序列参数集)同样重要的结构。PPS包含了一些与解码特定图像(或一组图像)相关的参数,这些参数通常在整个视频序列中保持不变,或者在需要时更新。PPS与SPS一起,为解码器提供了解码视频流所需的必要信息。以下是PPS的具体作用:

  1. PPS包含了应用于单个图像或一组图像(例如,某个GOP中的所有图像)的编码参数。这些参数用于指导解码器如何处理和解码这些图像。

  2. PS定义了用于图像的熵编码模式,包括CAVLC(Context-Adaptive Variable Length Coding)和CABAC(Context-Adaptive Binary Arithmetic Coding)。这些模式影响压缩效率和解码复杂度。

1.3 SODB和RBSP关系

SODB(String Of Data Bits)是原始编码数据,也就是SODB是由VCL生成的、最核心的编码数据位序列。这些比特流可能是不等长的,不一定是 8 的倍数。

RBSP(Raw Byte Sequence Payload)是在 SODB 的基础上形成的,它在 SODB 的末尾添加了结尾比特(RBSP trailing bits),以确保字节对齐。

具体来说,RBSP 的结尾比特是一个比特的“1”,然后可能会填充一些比特“0”,直到 RBSP 的长度是 8 的倍数为止。这样做的目的是为了保证 RBSP 的字节对齐性,以便于在传输和存储时的处理。

alt text

2 Annex-B与AVCC

H.264码流分为AVCC(Advanced Video Coding Configuration)与Annex-B两种组织格式。两种不同的方式分割NALU单元

  • AVCC格式 也叫AVC1格式,MPEG-4格式,字节对齐。用于mp4/flv/mkv等封装中。对应GStreamer h264parse 中的 stream-format:avc

  • Annex-B格式 也叫MPEG-2 transport stream format格式(ts格式), ElementaryStream格式。用于TS流中(以及使用TS作为切片的hls格式中)。对应GStreamer h264parse 中的 stream-format:byte-stream

alt text

这两种格式的区别有哪些,为什么要搞多种格式:

  1. NALU的分割方式不同(原因在于媒体可分为本地文件和直播流):

    • 如果是本地文件,则我们只需要读取一次SPS,PPS的信息,然后就可以一直进行解码了,所以将SPS PPS等信息放到文件的头部,打开文件,先读取这些信息初始化解码器,然后就可以顺利的解码了;其次本地文件不存在丢包或则中途进入一说,所有按照格式读取的话肯定能读取到NAL头的长度,所以像FLV,MP4,MKV这些常用的本地存储方式都用的AVCC封装。

    • 如果是直播流,那我们如果放到头部的话,中途播放的用户是无法接收到SPS PPS信息,无法初始化解码器,所以必须每隔一段时间发送一次SPS PPS等信息,一般是放在IDR帧之前进行发送,所以如mpeg-ts 这种常用的直播流就是使用Annex-B结构。

  2. SPS/PPS的数据结构不同:

    • AVCC格式使用NALU长度(固定字节,字节数由extradata中的信息给定)进行分割,在封装文件或者直播流的头部包含extradata信息(非NALU),extradata中包含NALU长度的字节数以及SPS/PPS信息。

    • Annex-B格式使用start code进行分割,start code为0x000001或0x00000001,SPS/PPS作为一般NALU单元以start code作为分隔符的方式放在文件或者直播流的头部。

2.1 Annex-B格式的NALU

下图是 Annex-B 格式 H.264码流

alt text

alt text

alt text

2.2 avcC格式的NALU

alt text

extradata部分内容如下:

alt text

比如MP4视频文件中的这部分,这就是extradata:包含了SPS,PPS信息、length占用多少个字节(一般都是4字节,表示NALU端的长度)。

2.2.1 分析avc流格式的mp4

/assets/Video/01_H264编码原理/video/output.mp4 为例:

下面画线部分就是extradata

alt text

分析length部分

alt text

3 slice

Slice,或者切片,是H.264编码中的一个基本单位,它包含了一系列的宏块(macroblocks),这些宏块共同构成了视频帧的一部分。在H.264编码中,一个视频帧可以被划分为一个或多个Slice。每个Slice都是独立编码的,这意味着它们可以被独立解码,不依赖于其他Slice的信息。

alt text

PS 是一个 NALU、PPS 是一个 NALU、每一个 Slice 也是一个 NALU。每一个 NALU 又都是由一个 1 字节的 NALU Header 和若干字节的 NALU Data 组成的。而对于每一个 Slice NALU,其 NALU Data 又是由 Slice Header 和 Slice Data 组成,并且 Slice Data 又是由一个个 MB Data 组成。其结构如下:

alt text

参考

AVCC参考

参考1:H264/H265的两种格式Annex B、AVCC(H264)/HVCC(H265)

参考2:H.264流媒体协议格式中的Annex B格式和AVCC格式深度解析

分析软件

Elecard StreamAnalyer

Ghex