一、H264编码原理——概述
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单元
SPS,PPS,IDR都是NALU单元,只不过是不同类型。
1.1 序列参数集SPS
SPS(Sequence Parameter Set,序列参数集)是一个关键的结构,用于存储一系列编码器的设置,这些设置在整个视频序列(或多个序列)中是恒定的。SPS包含了描述视频序列特性的信息,对于解码器正确解码视频至关重要。以下是SPS的主要作用:
-
图像尺寸(宽度和高度)
-
帧速率
-
指定了编码器所使用的Profile(如Baseline、Main、High等)和Level(如1.0, 2.1, 4.0等)。这些参数定义了编码器支持的功能和限制(如最大分辨率、最大比特率等)。
-
最大参考帧数量、宏块尺寸等。
1.2 图像参数集PPS
PPS(Picture Parameter Set,图像参数集)是与SPS(序列参数集)同样重要的结构。PPS包含了一些与解码特定图像(或一组图像)相关的参数,这些参数通常在整个视频序列中保持不变,或者在需要时更新。PPS与SPS一起,为解码器提供了解码视频流所需的必要信息。以下是PPS的具体作用:
-
PPS包含了应用于单个图像或一组图像(例如,某个GOP中的所有图像)的编码参数。这些参数用于指导解码器如何处理和解码这些图像。
-
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 的字节对齐性,以便于在传输和存储时的处理。
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
这两种格式的区别有哪些,为什么要搞多种格式:
-
NALU的分割方式不同(原因在于媒体可分为本地文件和直播流):
-
如果是本地文件,则我们只需要读取一次SPS,PPS的信息,然后就可以一直进行解码了,所以将SPS PPS等信息放到文件的头部,打开文件,先读取这些信息初始化解码器,然后就可以顺利的解码了;其次本地文件不存在丢包或则中途进入一说,所有按照格式读取的话肯定能读取到NAL头的长度,所以像FLV,MP4,MKV这些常用的本地存储方式都用的AVCC封装。
-
如果是直播流,那我们如果放到头部的话,中途播放的用户是无法接收到SPS PPS信息,无法初始化解码器,所以必须每隔一段时间发送一次SPS PPS等信息,一般是放在IDR帧之前进行发送,所以如mpeg-ts 这种常用的直播流就是使用Annex-B结构。
-
-
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码流
2.2 avcC格式的NALU
extradata部分内容如下:
比如MP4视频文件中的这部分,这就是extradata:包含了SPS,PPS信息、length占用多少个字节(一般都是4字节,表示NALU端的长度)。
2.2.1 分析avc流格式的mp4
以 /assets/Video/01_H264编码原理/video/output.mp4 为例:
下面画线部分就是extradata
分析length部分
3 slice
Slice,或者切片,是H.264编码中的一个基本单位,它包含了一系列的宏块(macroblocks),这些宏块共同构成了视频帧的一部分。在H.264编码中,一个视频帧可以被划分为一个或多个Slice。每个Slice都是独立编码的,这意味着它们可以被独立解码,不依赖于其他Slice的信息。
PS 是一个 NALU、PPS 是一个 NALU、每一个 Slice 也是一个 NALU。每一个 NALU 又都是由一个 1 字节的 NALU Header 和若干字节的 NALU Data 组成的。而对于每一个 Slice NALU,其 NALU Data 又是由 Slice Header 和 Slice Data 组成,并且 Slice Data 又是由一个个 MB Data 组成。其结构如下:
参考
AVCC参考
参考1:H264/H265的两种格式Annex B、AVCC(H264)/HVCC(H265)
参考2:H.264流媒体协议格式中的Annex B格式和AVCC格式深度解析
分析软件
Elecard StreamAnalyer
Ghex