系统化学习 H264视频编码(05)码流数据及相关概念解读
说明:我们参考黄金圈学习法(什么是黄金圈法则?->模型 黄金圈法则,本文使用:why-what)来学习音H264视频编码。本系列文章侧重于理解视频编码的知识体系和实践方法,理论方面会更多地讲清楚 音视频中概念的起源以及各个概念的联系。知其然,知其所以然。同时更强调知识系统的建立。
针对本文,我们主要研究 H.264码流数据结构及相关概念。包括VCL层(Video Coding Layer,视频数据编码层)及其相关概念宏块、片等,NAL层(Network Abstraction Layer,视频数据网络抽象层)及其相关概念SODB、RBSP、EBSP和NALU等;NALU详细信息解读以及Annex格式和RTP格式解读。
1 H264码流数据解读
H.264码流按照功能分为两层:视频编码层和网络提取层。即VCL层(Video Coding Layer,视频数据编码层)和NAL层(Network Abstraction Layer,视频数据网络抽象层)。
那么为什么要这样分层呢?这样的分层设计主要是为了满足不同的需求和优化视频数据的存储与传输。下面是分层设计的几个主要原因:
- 模块化设计:分层允许将视频编码的复杂性与网络传输的需求分离开来,使得每个层次可以独立优化和更新,而不影响另一层。
- 灵活性和扩展性:视频编码层专注于视频数据的有效压缩,而网络提取层则处理数据的封装、同步、错误恢复等问题,以适应不同的网络环境。
- 适应不同的网络条件:网络提取层可以根据网络带宽、延迟和丢包率等条件,对视频数据进行适当的处理,如数据分割、打包、传输和重组。
- 支持多种传输协议:通过分层,H.264码流可以更容易地适配多种网络传输协议,如RTP、MPEG-TS、HLS等,而无需修改编码层的实现。
- 提高错误恢复能力:网络提取层可以实现如FEC(前向纠错)等机制,增强视频流在不可靠网络中的传输鲁棒性。
- 支持随机访问和快速启动:通过在网络提取层插入关键帧和参数集的重复,可以支持视频流的快速启动和随机访问点的快速定位。
- 降低复杂性:将视频编码的复杂性限制在编码层,可以使得编码器设计更加集中和高效,而网络提取层则专注于数据的传输和提取。
- 便于实现和标准化:分层使得H.264标准更容易实现和标准化,因为每个层次可以有明确的规范和接口。
- 支持多种应用场景:不同的应用场景可能对视频数据的存储和传输有不同的需求,分层设计可以更好地满足这些需求。
- 提高兼容性:分层设计允许旧的系统和设备通过升级网络提取层来兼容新的编码技术和标准。
总的来说,视频编码层和网络提取层的分层设计是为了实现一个更加灵活、高效、可靠的视频编码和传输系统,以适应不断发展的技术和多样化的应用需求。
1.1 VCL层解读
VCL层 对视频原始数据进行压缩。H264视频序列可以理解为一系列的帧图像数据,将宏块有组织,有结构,有顺序的形成一系列的码流。这种码流可以通过InputStream网络流的数据进行传输,也可以封装成一个文件进行保存 。其中一帧图像从大到小依次拆解为:一帧图像->slice片组->slice片->宏块->像素。VCL结构关系如下图所示:

这里着重说明下涉及到的2个概念:片和宏块。具体如下:
-
宏块(Macroblock): 宏块是视频编码中的基本处理单元,通常由16x16像素的亮度数据和两个8x8像素的色度数据块组成(相对于4:2:0色度抽样)。宏块是预测、变换和量化操作的最小单位。
-
子块:子块是宏块的子单位,可以有不同的尺寸,例如8x8、8x4、4x8或4x4像素。在宏块内,亮度数据可以被进一步划分为子块进行处理,尤其是在变换(如DCT)和量化阶段。色度数据通常也按照亮度宏块的划分方式被划分为相应的子块。
- 宏块和子块之间的关系:宏块是由多个子块组成的。例如,在4:2:0色度抽样中,一个亮度宏块可以被划分为4个8x8像素的子块。宏块内的每个子块可以独立进行变换和量化处理,这有助于提高编码效率和适应不同的图像内容。在帧内编码中,宏块的每个子块通常会使用相同的变换和量化参数;而在帧间编码中,宏块可以包含不同类型的子块,例如,某些子块可能使用运动补偿预测,而其他子块可能不使用。
-
宏块和子块在编码过程中的应用:在编码过程中,宏块是进行预测、运动估计和残差编码的基本单元。子块的使用允许编码器对图像的不同区域应用不同的处理策略,以适应图像的局部特性,如边缘、纹理等。
-
宏块和子块在编码效率中的意义:通过合理地划分宏块和子块,编码器可以更有效地利用变换和量化技术来减少数据量,同时保持图像质量。两者的结合使用,使得视频编码算法能够灵活地适应不同的图像内容和编码需求。
-
-
片(Slice): 片是视频帧中的一个逻辑分段,可以包含一个或多个宏块。编码器可以根据内容的复杂性或编码策略将帧分割成多个片。每个片可以独立解码,有助于错误恢复和并行处理。片的分类如下:
- I片(Intra-coded Slice): I片,或称为内码片,完全由帧内编码的宏块组成。帧内编码意味着每个宏块仅使用其自身的像素数据进行编码,不依赖于其他帧的数据。I片通常用于关键帧,即在视频序列中用于参考的帧。
- P片(Predictive-coded Slice): P片,或称为预测编码片,由P宏块组成,这些宏块使用前向时间预测来编码。P片可包含P和I宏块,P宏块可以引用前面的I片或P片中的宏块来减少冗余,从而提高压缩效率。
- B片(Bidirectional-coded Slice): B片,或称为双向预测编码片,由B宏块组成,这些宏块使用双向时间预测来编码。B片可包含B和I宏块,B宏块可以引用前后两个方向的帧(包括同一帧内的其他片)来进一步减少时间上的冗余。
- 其他类型的片: 除了I、P、B片之外,还可能有其他类型的片,例如SP-Slice(Switching P-Slice)和SI-Slice(Switching I-Slice),这些片类型用于特定的编码场景,如场景切换或帧内/帧间编码的切换。
这些概念在视频编码中非常重要,因为它们决定了编码的复杂性、压缩效率和解码性能。通过合理地使用不同类型的宏块和片,编码器可以适应不同的视频内容和编码需求。
1.2 NAL层解读
NAL层: 它的作用是H264码流需要在网络上传输,在传输的过程每个包以太网是1500字节,而H264的帧往往会大于1500字节,所以要进行拆包,将一个帧拆成多个包进行传输,所有的拆包或者组包都是通过NAL层去处理的。NAL的目的可以理解为将VCL的数据封装后进行传输。NALU解读如下图所:

码流中 SODB、RBSP、EBSP和NALU 的概念及关系
SODB、RBSP、EBSP和NALU是一些专业术语,它们与编码的比特流和网络抽象层有关。接下来用一张图表示它们之间的关系。如下所示:

下面是这些术语的描述和它们之间的关系:
-
SODB(Sequence of Data Bits):SODB是数据比特的序列,长度不一定是8的倍数.它是由VCL层产生的.因为非8的倍数所以处理比较麻烦。这就导致码流数据写完后,最后写入的数据量不满一个字节。所以编码时要在未加工过的码流后,添加一个值等于1的尾部来表示码流的结束,该位称为停止位(rbsp_stop_one_bit)。然后为了字节对齐,在停止位(值为1)之后添加0位使得8位对齐,如上图所示。
-
RBSP(Raw Byte Sequence Payload):RBSP是EBSP去掉所有的填充字节(如H.264编码中的零字节填充)后的数据。RBSP是EBSP的一个子集,用于在解码过程中去除填充字节,以便正确解码原始数据。
-
EBSP(Encapsulate Byte Sequence Payload):EBSP是编码后的比特流有效载荷,它包含了实际的编码数据,但不包括任何头部信息或填充数据。EBSP是编码过程中生成的原始数据,包含了视频或音频帧的编码信息。
-
NALU(Network Abstraction Layer Unit ):本质上就是NAL Header+EBSP,即在EBSP的基础上加网络头。NALU是视频编码数据的封装单元,用于将编码后的数据分割成独立的、适合网络传输的包。每个NALU包含一个头部和有效载荷(Payload)。头部信息包括NALU类型、序列参数集(SPS)或图像参数集(PPS)的引用等。NALU类型定义了其内容的性质,例如视频帧的编码数据、序列参数集、图像参数集或其他控制信息。NALU设计为可以独立解码,这有助于错误恢复和并行处理。它的数据结构。
2 NALU 码流信息详细解读
接下来更详细地解读 NALU码流。NALU包含header(头信息)和数据信息。和前面了解到 NALU 数据实际上就是EBSP,EBSP去掉所有的填充字节,处理一下得到RBSP。因此NALU数据部分我们着重分析和关注RBSP的具体内容。
2.1 NALU Header(头部信息)解读
NALU Header整体只占据一个字节。分别为:

其中:
- forbidden_zero_bit:占1个Bit,当它为0时,解码器对这个NALU正常进行解码;当它不为 0 时,表示网络传输过程中,当前NALU中可能存在错误,解码器可以不解码这个NALU。
- nal_ref_idc:占2个Bit,取值范围为0~3,代表当前这个NALU的重要性,取值越大,代表当前NALU越重要,就需要优先被保护。
- nal_unit_type:占5个Bit,代表NALU Header后面的EBSP数据结构的类型,这里可以理解为NALU的数据类型。EBSP的数据类型共2^5=32种。32种类型解读如下图所示:
-
H264中 32种NALU数据的类型
2.2 NALU Data(数据信息)解读
这里着重分析RBSP码流数据信息。RBSP数据信息主要分为2大类:
- 编码后的视频帧数据:编码后的视频帧数据指的是经过H.264编码器处理后,用于表示视频帧的压缩数据。这些数据以一种高效的格式存储,以便减少所需的存储空间和传输带宽。编码后的视频帧数据主要包括:I帧、P帧、B帧,它们是属于哥伦布编码的。
- 一些关键的元数据:解码和显示视频帧所需的额外信息。比如 序列参数集(SPS, Sequence Parameter Set,包含了整个视频序列的全局参数,如图像尺寸、帧率、色彩空间等。SPS是解码器配置视频序列解码参数的关键信息)和 图像参数集(PPS, Picture Parameter Set,包含了单个图像或一组图像的参数,如编码模式的选择、去块滤波器的使用、量化参数等。PPS为解码器提供了图像级别的配置信息。)
这些数据被封装在NAL单元中,并通过添加特定的字节对齐比特和防止竞争字节,以适应网络传输和存储的需求。
有了对NALU数据的了解,在此基础上,我们再继续了解2种常见的数据封装格式。
3 Annex格式和RTP格式解读
Annex格式和RTP(Real-time Transport Protocol)是两种不同的数据封装格式,它们在H.264视频流的组织和传输中扮演不同的角色。
3.1 Annex格式
Annex格式,也称为Annex B格式,是H.264标准中推荐的一种码流组织方式,主要用于存储介质或实时播放。它的特点包括:
- 使用特定的开始码(Start Code)来标识每个NAL单元(NALU)的开始,这些开始码可以是3字节的
0x000001
或4字节的0x00000001
。 - 通常在关键帧前周期性地重复序列参数集(SPS)和图像参数集(PPS),以支持视频流的随机访问。
- 适用于连续的数据传输,如视频文件或实时流媒体,因为它允许解码器从视频流的随机点开始解码 68。
3.2 RTP格式
RTP格式是为网络传输设计的,特别是适用于IP网络。RTP格式的特点包括:
- 将NALU封装在RTP包中,每个RTP包包含一个或多个NALU。
- RTP包头包含了用于实时传输的关键信息,如时间戳、序列号等。
- 支持NALU的分割和组装,以适应不同的网络环境和传输效率。
- 根据RFC 3984,RTP封装的H.264视频流可以有效地在IP网络上进行传输和控制 12。
3.3 Annex格式和RTP格式之间关系与差异
- 关系:Annex格式和RTP格式都可以包含H.264的NALU,但是它们的封装方式和应用场景不同。Annex格式更适合存储和实时播放,而RTP格式更适合网络传输。
- 差异:
- 开始码:Annex格式使用固定的开始码来标识NALU的边界,而RTP格式使用RTP包头和可能的NALU长度前缀。
- 实时性:RTP格式提供了更好的实时传输支持,包括时间戳和序列号等信息。
- 应用场景:Annex格式常用于视频文件和实时流,RTP格式用于基于IP的网络传输。
总的来说,Annex格式和RTP格式都是H.264视频流的有效封装方式,选择哪一种取决于具体的应用需求和传输环境。
相关文章:

系统化学习 H264视频编码(05)码流数据及相关概念解读
说明:我们参考黄金圈学习法(什么是黄金圈法则?->模型 黄金圈法则,本文使用:why-what)来学习音H264视频编码。本系列文章侧重于理解视频编码的知识体系和实践方法,理论方面会更多地讲清楚 音视频中概念的…...

【VMware】如何演示使用U盘在VMware虚拟机上安装Windows11
一、前置准备 在开始使用U盘演示在VMware虚拟机上装Windows11前,我们需要做以下前置的准备: 已制作好的Windows引导盘;WMware软件 如何制作Windows引导盘? 推荐参考: 【建议收藏】2024年最新Windows系统重装教程&…...

HanLP和Jieba区别
HanLP和Jieba都是中文分词工具,但它们在多个方面存在区别。以下是对两者区别的详细分析: 一、开发背景与语言支持 HanLP:由大连理工大学自然语言处理与社会人文计算实验室开发,是一个开源的自然语言处理工具包。它主要使用Java语…...

荒原之梦考研:考研二战会很难吗?
考研二战是不是很难,其实很大程度上取决于我们自己,我们能否认清自己的优势,能否指定和执行合理的计划,有没有强大的心理支撑等,都是决定考研二战能否成功,或者能否比较轻松的成功的关键。 在本文中&#…...

【Git企业级开发实战指南①】Git安装、基本操作!
目录 一、Git是什么?1.1特点1.2功能1.3基本概念 二、Git安装2.1Ubuntu下安装2.2Centos下安装Git 三、Git基本操作3.1创建git本地仓库3.2配置Git3.3 工作区&暂存区&版本库3.4 实操案例3.4.1添加文件 3.5 修改文件3.6版本回退3.7查看历史操作日志3.7撤销修改3…...

Leetcode 3239. Minimum Number of Flips to Make Binary Grid Palindromic I
Leetcode 3239. Minimum Number of Flips to Make Binary Grid Palindromic I 1. 解题思路2. 代码实现 题目链接:3239. Minimum Number of Flips to Make Binary Grid Palindromic I 1. 解题思路 这一题思路上的话就是分别考察一下把所有行都变成回文所需要的fli…...

C++面试基础算法的简要介绍
C是一种广泛使用的编程语言,尤其在算法和数据结构的实现中占据重要地位。以下是对C基础算法的一些介绍,涵盖了排序、查找、搜索算法以及基本的遍历算法等方面。 排序算法 快速排序(Quick Sort) 快速排序是一种分而治之的排序算法…...

【Linux网络编程】套接字Socket(UDP)
网络编程基础概念: ip地址和端口号 ip地址是网络协议地址(4字节32位,形式:xxx.xxx.xxx.xxx xxx在范围[0, 255]内),是IP协议提供的一种统一的地址格式,每台主机的ip地址不同,一个…...

jvm方法返回相关指令ireturn,areturn,return等分析
正文 看图: 做的事情如下: 1:弹出当前的方法栈帧 2:获取上一个方法 3:从当前方法的操作数栈中获取执行结果,并推送到上一个方法的操作数栈中对应的伪代码: Override public void execute(Frame frame) {Thread thread frame.thread();Frame curren…...

宝塔部署springboot vue ruoyi前后端分离项目,分离lib、resources
1、“文件”中创建好相关项目目录,并将项目相关文件传到对应目录 例如:项目名称/ #项目总目录 api/ #存放jar项目的Java项目文件 manage/ #vue管理后端界面 …...

Python 基础教程:List(列表)的使用
《Python 基础教程:List(列表)的使用》 在 Python 中,列表是最基本的数据结构之一,它是一种有序的、可变的数据集合,可以包含任意类型的元素,包括数字、字符串、其他列表等。 1. 列表的创建 …...

kubebuilder常用标签
kubebuilder 标签是用于注解 Kubernetes CRD(Custom Resource Definition) 的标签,主要用于在 Operator SDK 和 Kubebuilder 框架中生成代码、验证规则以及自定义 CRD 的生成。以下是常用的 kubebuilder 标签: 1. 字段验证标签 …...

ChatTTS文本转语音本地部署结合内网穿透实现远程使用生成AI音频
文章目录 前言1. 下载运行ChatTTS模型2. 安装Cpolar工具3. 实现公网访问4. 配置ChatTTS固定公网地址 前言 本篇文章主要介绍如何快速地在Windows系统电脑中本地部署ChatTTS开源文本转语音项目,并且我们还可以结合Cpolar内网穿透工具创建公网地址,随时随…...

基于微信小程序的高校大学生信息服务平台设计与实现
基于微信小程序的高校大学生信息服务平台设计与实现 Design and Implementation of a College Student Information Service Platform based on WeChat Mini Program 完整下载链接:基于微信小程序的高校大学生信息服务平台设计与实现 文章目录 基于微信小程序的高校大学生信息…...

YOLOV8替换Lion优化器
YOLOV8替换Lion优化器 1 优化器介绍博客 参考bilibili讲解视频 论文地址:https://arxiv.org/abs/2302.06675 代码地址:https://github.com/google/automl/blob/master/lion/lion_pytorch.py """PyTorch implementation of the Lion …...

uniapp页面里面的登录注册模板
<!-- 账号密码登录页 --> <template><view class"page"><view class"uni-content"><view class"login-logo"><image :src"logo"></image></view><text class"title title-bo…...

C++新手入门学习教程(完整版)
以下教程覆盖了 C 学习的各个方面,适合初学者循序渐进地学习。学习过程中,建议初学者多做练习和项目,以加深对理论知识的理解。希望这个教程能为你提供一个清晰的学习路径。 目录 第一章:C 简介 1.1 C 的历史与演变 1.2 C 的特…...

Python 爬虫入门(六):urllib库的使用方法
Python 爬虫入门(六):urllib库的使用方法 前言1. urllib 概述2. urllib.request 模块2.1 发送GET请求2.2 发送POST请求2.3 添加headers2.4 处理异常 3. urllib.error 模块4. urllib.parse 模块4.1 URL解析4.2 URL编码和解码4.3 拼接URL 5. ur…...

个人开发神器,一应俱全,有你想要的!
哈喽,各位小伙伴们好,我是给大家带来各类黑科技与前沿资讯的小武。 经常有很多小伙伴问小武,是从哪里获取到这么多资源,其实除了熟知的吾爱、酷安等知名论坛集聚地,还有一些强大的资源聚合类软件也非常重要。 如之前安…...

电子电气架构 --- SOVD在域控制器的应用
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…...

React(四):DOCX文件在线预览
效果 注意 ⚠️注意:部分文件预览存在问题 依赖 $ yarn add docx-preview $ yarn add jszip源码 import ./index.scss; import {useRef} from react; import type {UploadRequestOption} from rc-upload/lib/interface; import {Upload, Button, message} from an…...

Java IO.字符集,流,缓冲流 转换流 对象操作流
一.字符集 如果使用字节流 , 把文本文件中的内容读取到内存时, 可能会出现乱码 如果使用字节流 , 把中文写入文本文件中 , 也有可能会出现乱码 读取n.txt"你好" 两个汉字 字节流读中文,每次只能读一部分所以出现了乱码 字符集(Character se…...

线性稳压器的内部电路与构成分析
线性稳压器的一般的引脚构成 线性稳压器基本上由VIN (输入)、VO (输出)、GND (接地)三个引脚构成。在输出可变的线性稳压器上添加了用于反馈输出电压的FB(反馈引脚)。 简单来说&am…...

Go语言实现多协程文件下载器
文章目录 前言流程图主函数下载文件初始化分片下载worker分发下载任务获取下载文件的大小下载文件分片错误重试项目演示最后 前言 你好,我是醉墨居士,最近在开发文件传输相关的项目,然后顺手写了一个多协程文件下载器,代码非常精…...

本地方法详解
本地方法(Native Methods)是指那些由Java程序调用,但其实现是用非Java语言(如C、C等)编写的方法。它们通常用于访问操作系统底层的功能或进行高效的计算,这些是Java本身不能直接实现的。下面详细解释本地方…...

每日新闻掌握【2024年8月3日 星期六】
2024年8月3日 星期六 农历六月廿九 大公司/大事件 微信地震预警全国上线 36氪获悉,国家地震烈度速报与预警工程已于7月25日正式通过国家验收。8月2日,在中国地震局指导下,中国地震台网中心、中央广播电视总台国家应急广播与腾讯联合推出“中…...

python入门基础篇(一)
基础篇 Python基础安装与配置Python环境理解Python解释器第一个Python程序:"Hello, World!" 基础语法注释与文档字符串变量与数据类型数字类型:整数、浮点数、复数字符串布尔值None值 运算符算术运算符比较运算符逻辑运算符赋值运算符位运算符…...

windows下在线预览服务kkFileView4.4.0问题记录
前几天找到一个开源项目:kkFileView,感觉可能以后可能会用到,所以尝试了下。 通过git下载下来,版本是4.4.0,通过idea打开项目,发现老是无法找到组件aspose-cad,版本是23.9. 找了好多文章&#x…...

Java:通过反射获取class类的属性
有如下一个普通类,我想获取他的所有属性值 package com.demo.bean;import lombok.Data;import java.util.List;Data public class UserBean {private String name;private Integer age;private List<String> tags; }可以通过反射的方式获取属性值 package c…...

07.FreeRTOS列表与列表项
文章目录 07. FreeRTOS列表与列表项1. 列表和列表项的简介2. 列表相关API函数3. 代码验证 07. FreeRTOS列表与列表项 1. 列表和列表项的简介 列表的定义: typedef struct xLIST {listFIRST_LIST_INTEGRITY_CHECK_VALUE /* 校验值 */volatile UBaseType_t uxN…...