跟音频编码一样,视频编码最主要的目的也是为了进行数据压缩,以此来降落数据传输和存储本钱。
以一起分辨率 720x1280(常说的 720P),帧率为 30 fps 的视频为例,如果不经由编码压缩,直接传输或存储原始的 RGB 数据,对应的码率是:720 1280 3 8 30 = 632.8125 Mbps (宽 高 像素字节数 字节比特数 帧数)。一分钟的韶光所须要的数据量是:632.8125 Mbps 60s = 4.63 GB。
这个数据量很大,须要很高的存储或传输本钱,因此须要采取编码压缩技能以减少码率。

常日,对信息进行压缩,可以从这几个方面动手:
1)信源包含的符号涌现概率的非均匀性,使得信源是可以被压缩的。熵编码就利用信源的统计特性进行码率压缩的编码办法。比如著名的哈夫曼编码(也是熵编码的一种),便是当信源中各符号的涌现概率都一样时编码效率最低。2)信源的干系性,使得信源是可以被压缩的。比如信息 A 和信息 B 的干系性,使得我们可以由信息 A 加残差 D(D = A - B) 来推导信息 B,这样只编码 A 和 D 来实现压缩,这便是所谓的差分编码技能。3)人的感知对不同信源的敏感度不一样,使得信源是可以被压缩的。对人感知不敏感的信息进行部分或全部忽略来实现压缩。要对视频进行编码,则紧张是研究视频数据中的冗余信息,并对其进行压缩。视频信息紧张包括这几个方面的冗余:
空间冗余:在同一张帧之中,相邻的像素之间常日有很强的相干性,这样的相干性即为空间上的冗余信息。韶光冗余:在视频信息中,相邻的帧与帧之间常日有很强的相干性,这样的相干性即为韶光上的冗余信息。编码冗余:视频中不同数据涌现的概率不同,欲编码的符号的几率分布是不屈均的。视觉冗余:人的视觉系统对某些细节不敏感。视觉上的冗余信息是指在人在不雅观看视频时,人眼无法察觉的信息。现在常见的视频编码格式有 3 个大的系列,分别由不同的组织主导制订:
1)ISO-MPEG/ITU-T 系列:由国际标准组织机构(ISO)下属的运动图象专家组(MPEG)和国际电传视讯同盟远程通信标准化组织(ITU-T)开拓的系列编码标准。
H.264,也被称为高等视频编码(Advanced Video Coding,简称 AVC),是一种被广泛利用的高精度视频的录制、压缩和发布格式。该标准引入了一系列新的能够大大提高压缩性能的技能,并能够同时在高码率端和低码率端大大超越以前的诸标准。H.265,也被称为高效率视频编码(High Efficiency Video Coding,简称 HEVC),是 H.264 的继任者。HEVC 被认为不仅提升图像质量,同时也能达到 H.264 两倍的压缩率(等同于同样画面质量下比特率减少了 50%),可支持 4K 分辨率乃至到超高画质电视,最高分辨率可达到 8192×4320(8K 分辨率),这是目前发展的趋势。H.266,也被称为多功能视频编码(Versatile Video Coding,简称 VVC),是 H.265 的继任者。VVC 对 8K 超高清、屏幕、高动态和 360 度全景视频等新的视频类型以及自适应带宽和分辨率的流媒体和实时通信等运用有了更好的支持。根据最近的 JVET 官方主不雅观测试结果,VVC 的均匀编码性能相对 HEVC 的提高已经可以达到 49%。2)AOM 系列:前身是由 Google 主导的 VPx 系列的编码标准。后续由多家公司组件成立了开放媒体同盟(Alliance for Open Media,AOM)连续开拓新的编码标准。
VP8,是一个开放的图像压缩格式,最早由 On2 Technologiesis 开拓,随后由 Google 发布。同时 Google 也发布了 VP8 编码的实做库:libvpx,以 BSD 授权条款的办法发布,随后也附加了专利利用权。而在经由一些辩论之后,终极 VP8 的授权确认为一个开放源代码授权。VP9,是 Google 供应的开源的免费视频编码格式,是 VP8 的后续版本。AV1,Alliance for Open Media Video 1 是由 AOM(Alliance for Open Media,开放媒体同盟)制订的一个开源、免版权费的视频编码格式,目标是办理 H.265 昂贵的专利用度和繁芜的专利授权问题并成为新一代领先的免版权费的编码标准。此外,AV1 是 Google 制订的 VP9 标准的继任者,也是 H.265 强有力的竞争者。3)AVS 系列:AVS(Audio Video coding Standard)是中国具备自主知识产权的系列编码标准。
AVS2,第二代数字音视频编解码技能标准(AVS2),其紧张运用目标是超高清晰度视频,支持超高分辨率(4K 以上)、高动态范围视频的高效压缩。AVS3,AVS3 增加了对 8K 分辨率的支持,该技能将利用于中心广播电视总台 8K 超高清频道。这里我们只对 H.264、H.265、H.266 做一下先容。
1、H.264 编码1.1、基本观点
1.1.1、句法元素分层构造
H.264 中,句法元素可以分为『序列』、『图像』、『片』、『宏块』、『子宏块』五个层次。
在 H.264 中,分层构造相较之前最大的不同是取消了序列层和图像层,并将原来属于序列和图像头部的大部分句法元素游离出来形成序列和图像两级参数集,别的的部分则放入片层。在这种机制下,由于参数集是独立的,可以被多次重发或者采取分外技能加以保护。参数集与参数集外部的句法元素处于不同信道中,这是 H.264 的一个建议,我们可以利用更安全但本钱更昂贵的通道来传输参数集。
领取音视频开拓资料:音视频流媒体高等开拓FFmpegWebRTCRTMPRTSPHLSRTP播放器
企鵝君羊994289133领取资料
1.1.2、软件和硬件编解码
编解码分为软编软解和硬编硬解:
软编/软解: CPU 处理。硬编/硬解: 利用显卡 GPU、专用 SDP 等其它芯片硬件处理。软编用的是 CPU 处理,优点是调节能力比较强,相对付硬编,软编可以通过参数调度可以在同一码率下编码出清晰度更高的视频,此外软编可以兼容性更好,可以适配所有设备,但缺陷是性能可能比较差,不如硬编速率快、功耗低。
软解相对付硬解,则是性能可能较差,不如硬解功耗低,但是兼容性更好,适配性更好。
目前移动运用大部分业务场景采取的编码策略是:手机端只管即便采取硬编编码出一起高清的视频,将高清视频发送给做事器,由做事器再进行软编转码为多路码率的视频,再通过 CDN 分发给不雅观看端。其余,安卓的一些低端机可能由于硬件问题对硬编支持不完善,这时候可以利用软编,或者硬编出错的情形可以切换为软编来兜底。当然有时候,对付一些性能优胜的高端机型或者编码时长不多的业务场景也可以优先用软编,例如录制 15 秒短视频的场景,首先韶光比较短并且机器性能高不怕 CPU 花费,这样相同码率可以再提高清晰度。
对付大部分的运用处景的解码策略则紧张采取硬解,用软解作为兜底。此外,对付一些硬解不支持的编码类型,可以利用软解,比如有的机型不支持 H.265 解码,则只能利用软解。
1.1.3、序列H.264 编码的办法可以这样理解:在视频中,一段韶光内相邻的图像的像素、亮度与色温的差别常日很小。以是没必要去对一段韶光内的每一幅图像都进行完全一帧的编码,而是可以选取这段韶光的第一帧图像进行完全编码,而下一幅图像只记录与第一帧完全编码图像的像素、亮度与色温等特色的差别即可,以此类推循环下去。
什么叫序列呢?上述的这段韶光内图像变革不大的图像集就可以称之为一个序列。序列可以理解为有相同特点的一段图像数据。但是如果某个图像与之前的图像变换很大,很难参考之前的帧来天生新的帧,那么就结束上一个序列,开始下一个序列。重复上述做法,天生新的一段序列。
1.1.4、帧类型H.264 构造中,一幅视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由 16x16 的 YUV 数据组成。宏块是 H.264 编码的基本单位。
在 H.264 协议内定义了三种帧,分别是 I 帧、B 帧与 P 帧。
1)I 帧
I 帧,即帧内编码图像帧,不参考其他图像帧,只利用本帧的信息进行编码。
I 帧的特点:
它是一个全帧压缩编码帧,将全帧图像信息进行压缩编码及传输;解码时仅用 I 帧的数据就可重构完全图像;I 帧描述了图像背景和运动主体的详情;I 帧不须要参考其他画面而天生;I 帧是 P 帧和 B 帧的参考帧,其质量直接影响到同组中往后各帧的质量;一样平常地,I 帧是图像组 GOP 的根本帧(第一帧),在一组中只有一个 I 帧;I 帧所占数据的信息量比较大。I 帧编码流程:
进行帧内预测,决定所采取的帧内预测模式;当前像素值减去预测值,得到残差;对残差进行变换和量化;变长编码和算术编码;重构图像并滤波,得到的图像作为其它帧的参考帧。2)P 帧
P 帧,即预测编码图像帧,利用之前的 I 帧或 P 帧,采取运动预测的办法进行帧间预测编码。
P 帧的预测与重构:P 帧因此 I 帧为参考帧,在 I 帧中找出 P 帧『某点』的预测值和运动矢量,取预测差值和运动矢量一起传送。在吸收端根据运动矢量从 I 帧中找出 P 帧『某点』的预测值并与差值相加以得到 P 帧『某点』样值,从而可得到完全的 P 帧。
P 帧特点:
P 帧是 I 帧后面相隔 1-2 帧的编码帧;P 帧采取运动补偿的方法传送它与前面的 I 或 P 帧的差值及运动矢量(预测偏差);P 帧属于前向预测的帧间编码,它只参考前面最靠近它的 I 帧或 P 帧;P 帧可以是其后面 P 帧的参考帧,也可以是其前后的 B 帧的参考帧;由于 P 帧是参考帧,它可能造成解码缺点的扩散;由于是差值传送,P 帧的压缩比较高。P 帧编码的基本流程:
进走运动估计,打算采取帧间编码模式的率失落真函数值。P 帧只参考前面的帧;进行帧内预测,选取率失落真函数值最小的帧内模式与帧间模式比较,确定采取哪种编码模式;打算实际值和预测值的差值;对残差进行变换和量化;若编码,如果是帧间编码模式,编码运动矢量。3)B 帧
B 帧,即双向预测编码图像帧,供应最高的压缩比,它既须要之前的图像帧(I 帧或 P 帧),也须要后来的图像帧(P 帧),采取运动预测的办法进行帧间双向预测编码。
B 帧的预测与重构:B 帧以前面的 I 或 P 帧和后面的 P 帧为参考帧,找出 B 帧『某点』的预测值和两个运动矢量,并取预测差值和运动矢量传送。吸收端根据运动矢量在两个参考帧中找出预测值并与差值求和,得到 B 帧『某点』样值,从而可得到完全的 B 帧。
B 帧特点:
B 帧是由前面的 I 或 P 帧和后面的 P 帧来进行预测的;B 帧传送的是它与前面的 I 或 P 帧和后面的 P 帧之间的预测偏差及运动矢量;B 帧是双向预测编码帧;B 帧压缩比最高,由于它只反响两参考帧间运动主体的变革情形,预测比较准确;B 帧不是参考帧,不会造成解码缺点的扩散。B 帧编码的基本流程:
进走运动估计,打算采取帧间编码模式的率失落真函数值。B 帧可参考后面的帧;进行帧内预测,选取率失落真函数值最小的帧内模式与帧间模式比较,确定采取哪种编码模式;打算实际值和预测值的差值;对残差进行变换和量化;若编码,如果是帧间编码模式,编码运动矢量。率失落真函数的干系简介:
有损压缩算法,性能由编码输出的比特率和失落真共同决定。
编码的目的:便是在担保一定视频质量的条件下只管即便减少编码比特率,或在一定编码比特率限定条件下只管即便地减
编码器的事情:根据以上率失落真准则找到最佳编码参数。
信息论中率失落真观点:在许可一定程度失落真的条件下,能够把信源信息压缩到什么程度,即最少须要多少比特数才能描述信源。由此得到率失落真函数:R(D) = min I(X, Y),它给出了限定失落真条件下信息压缩许可的下界。但其在视频编码中难以运用,由于各种概率和条件概率未知,只能作为理论值。
视频编码中的率失落真曲线:为了研究视频码率与视频质量的平衡。由于系统性,不能达到理论上的 R(D) 值,只能由不同的编码参数(如 QP 和选择的模式)得到有限的 (R, D) 可操作点,形成凸包络。
视频编码中的率失落真优化(RDO):遍历所有的参数候选模式对视频进行编码,知足码率限定的失落真最小的一组参数集作为最优的视频编码参数。每一层级都找出,终极使整体系统性能最优。这里假设了无干系性的独立优化,如干系性较强则共同优化。
1.1.5、DTS 和 PTSDTS、PTS 的观点如下所述:
DTS(Decoding Time Stamp):即解码韶光戳,这个韶光戳的意义在于见告播放器该在什么时候解码这一帧的数据。PTS(Presentation Time Stamp):即显示韶光戳,这个韶光戳用来见告播放器该在什么时候显示这一帧的数据。须要把稳的是:虽然 DTS、PTS 是用于辅导播放真个行为,但它们是在编码的时候由编码器天生的。
当视频流中没有 B 帧时,常日 DTS 和 PTS 的顺序是同等的。但如果有 B 帧时,就回到了我们前面说的问题:解码顺序和播放顺序不一致了。
比如一个视频中,帧的显示顺序是:I B B P,现在我们须要在解码 B 帧时知道 P 帧中信息,因此这几帧在视频流中的顺序可能是:I P B B,这时候就表示出每帧都有 DTS 和 PTS 的浸染了。DTS 见告我们该按什么顺序解码这几帧图像,PTS 见告我们该按什么顺序显示这几帧图像。顺序大概如下:
Stream: I P B B DTS: 1 2 3 4 PTS: 1 4 2 3
1.1.6、GOPGOP(Group Of Pictures)是图像组的观点,它指的是视频编码序列中两个 I 帧之间的间隔。常日意义上的 GOP 由 I 帧开始,到下一个 I 帧之前的帧结束。严格意义上讲,这个 I 帧是一个 IDR 帧。
H.264 利用的是封闭 GOP(Closed GOP),即在一个 GOP 中所有帧的解码不依赖该 GOP 外的其他帧,除了第一帧必须是 I 帧,其他帧可以是 P 帧或 B 帧。
上图中是一个 GOP 为 15 帧的例子,如果视频的帧率是 15 fps,那么这个 GOP 便是 1s 时长。
关键帧的间隔调节会影响 GOP 的长度,进而影响到读取 GOP 的速率,为防止运动变革,一个 GOP 组内帧数不宜取多。如果关键帧的间隔设置过大的话(GOP 长度过大),在必须用到关键帧的场合就可能被迫利用 B/P 帧来代替,这就会降落画面质量。
1.1.7、IDR 帧IDR 帧全称叫做 Instantaneous Decoder Refresh,是 I 帧的一种。IDR 帧的浸染是急速刷新,重新算一个新的序列开始编码,使缺点不致传播。I 帧有被跨帧参考的可能,但 IDR 帧不会。
比如:
IDR1 P2 B3 B4 P5 B6 B7 I8 B9 B10 P11 B12 B13 P14 B15 B16
这里的 B8 可以跨过 I8 去参考 P7。
IDR1 P2 B3 B4 P5 B6 B7 IDR8 B9 B10 P11 B12 B13 P14 B15 B16
这里的 B9 就不可以参考 IDR8 前面的帧。
H.264 引入 IDR 帧是为理解码的重同步,当解码器解码到 IDR 帧时,立即将参考帧行列步队清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列涌现缺点,在这里可以得到重新同步的机会,不会将缺点传导下去。IDR 帧之后的帧永久不会利用 IDR 帧之前的帧来解码。
以是总结下来,IDR 帧有如下特性:
IDR 帧一定是 I 帧,严格来说 I 帧不一定是 IDR 帧(但一样平常 I 帧便是 IDR 帧);对付 IDR 帧来说,在 IDR 帧之后的所有帧都不能引用任何 IDR 帧之前的帧的内容。与此相反,对付普通的 I 帧来说,位于其之后的 B 和 P 帧可以引用位于普通 I 帧之前的 I 帧(普通 I 帧有被跨帧参考的可能);播放器永久可以从一个 IDR 帧播放,由于在它之后没有任何帧引用之前的帧。因此,视频开头的 I 帧一定是 IDR 帧;一个封闭类 GOP 的开头的 I 帧也一定是 IDR 帧。1.1.8、压缩办法H.264 采取的核心算法是『帧内压缩』和『帧间压缩』,帧内压缩是天生 I 帧的算法,帧间压缩是天生 B 帧和 P 帧的算法。
帧内压缩也称为空间压缩。当压缩一帧图像时,仅考虑本帧的数据而不考虑相邻帧之间的冗余信息,这实际上与静态图像压缩类似。帧内一样平常采取有损压缩算法,由于帧内压缩是编码一个完全的图像,以是可以独立的解码、显示。帧内压缩一样平常达不到很高的压缩率,跟编码 JPEG 差不多。
帧间压缩的事理是:相邻几帧的数据有很大的干系性,或者说前后两帧信息变革很小的特点。也即连续的视频其相邻帧之间具有冗余信息,根据这一特性,压缩相邻帧之间的冗余量就可以进一步提高压缩量,减小压缩比。帧间压缩也称为韶光压缩,它通过比较韶光轴上不同帧之间的数据进行压缩。帧间压缩一样平常是无损的。帧差值算法是一种范例的韶光压缩法,它通过比较本帧与相邻帧之间的差异,仅记录本帧与其相邻帧的差值,这样可以大大减少数据量。
编码压缩的步骤大致如下:
分组,也便是将一系列变换不大的图像归为一个组,也便是一个序列,也便是 GOP;定义帧,将每组的图像帧归分为 I 帧、P 帧和 B 帧三种类型;预测帧,以 I 帧做为根本帧,以 I 帧预测 P 帧,再由 I 帧和 P 帧预测 B 帧;数据传输,末了将 I 帧数据与预测的差值信息进行存储和传输。1.2、分层构造H.264 的紧张目标是为了有高的视频压缩比和良好的网络亲和性,为了达成这两个目标,H.264 的办理方案是将系统框架分为两个层面:『视频编码层面(VCL)』和『网络抽象层面(NAL)』。
视频编码层(VCL),是对视频编码核心算法过程、子宏块、宏块、片等观点的定义。这层紧张是为了尽可能的独立于网络来高效的对视频内容进行编码。编码完成后,输出的数据是 SODB(String Of Data Bits)。网络适配层(NAL),是对图像序列、图像等片级别以上的观点的定义。这层卖力将 VCL 产生的比特字符串适配到各种各样的网络和多元环境中。该层将 VCL 层输出的 SODB 数据打包成 RBSP(Raw Byte Sequence Payload)。SODB 是编码后的原始数据,RBSP 是在原始编码数据后面添加了却尾比特,一个比特 1 和多少个比特 0,用于字节对齐。然后再在 RBSP 头部加上 NAL Header 来组成一个一个的 NAL 单元。
从视频编码层(VCL)角度去看 H.264 的构造:
从网络适配层(NAL)角度去看 H.264 的构造:
1.3、编码工具
下图为一个范例的视频编码器。在进行当前旗子暗记编码时,编码器首先会产生对当前旗子暗记做预测的旗子暗记,称作预测旗子暗记(Predicted Signal),预测的办法可以是韶光上的帧间预测(Inter Prediction),亦即利用先前帧的旗子暗记做预测,或是空间上的帧内预测(Intra Prediction),亦即利用同一张帧之中相邻像素的旗子暗记做预测。得到预测旗子暗记后,编码器会将当前旗子暗记与预测旗子暗记相减得到残差旗子暗记(Residual Signal),并只对残差旗子暗记进行编码,如此一来,可以去除一部分韶光上或是空间上的冗余信息。接着,编码器并不会直接对残差旗子暗记进行编码,而是先将残差旗子暗记经由变换(常日为离散余弦变换)然后量化以进一步去除空间上和感知上的冗余信息。量化后得到的量化系数会再透过熵编码,去除统计上的冗余信息。
H.264 的编解码流程如下:
1.3.1、帧内预测
一样平常来说,对付一帧图像,相邻两个像素的亮度和色度值之间常日是比较靠近的,也便是颜色是逐渐变革的,不会一下子突变成完备不一样的颜色。而进行视频编码,目的便是利用这个干系性,来进行压缩。帧内预测便是基于这个事理。
假设现在我们要对一个像素 X 进行编码,在编码这个像素之前,我们找到它附近的像素作为参考像素 X’,根据 X’ 我们经由预测算法得到对像素 X 的预测值 Xp,然后我们再用 X 减去 Xp 得到二者的残差 D,并用这个残差 D 代替 X 进行编码,起到节省码率的浸染。末了,我们还用预测值 Xp 和残差 D 相加得到 X’ 用于下一个像素的预测。这个便是我们用帧内预测进行编码压缩的大体思想。
在实际编码中,我们固然可以按像素为单位进行预测,但这样效率比较低,以是在 H.264 标准中提出按照块为单位进行打算。一个宏块是 16x16 像素,它可以分成子块,最小是 4x4 的(这个大小是对付亮度编码而言,至于色度编码,4:2:0 采样格式的色度宏块的长和宽都是亮度宏块的一半),这样能大大提高打算速率。
在帧内预测模式中,预测块是基于已编码重修的块和当前块形成的。对亮度像素而言,预测块用于 4×4 子块或者 16×16 宏块的干系操作。4×4 亮度子块有 9 种可选预测模式,独立预测每一个 4×4 亮度子块,适用于带有大量细节的图像编码;16×16 亮度块有 4 种预测模式,预测全体 16×16 亮度块,适用于平坦区域图像编码;色度块也有 4 种预测模式,类似于 16×16 亮度块预测模式。编码器常日选择使预测块和编码块之间差异最小的预测模式。
1.3.2、帧间预测帧间预测便是时域预测,旨在肃清时域冗余信息,大略点说便是利用之前编码过的图像来预测要编码的图像。个中涉及到两个主要的观点:运动估计和运动补偿。
运动估计是探求当前编码的块在已编码的图像(参考帧)中的最佳对应块,并且打算出对应块的偏移(运动矢量)。
运动补偿是根据运动矢量和帧间预测方法,求得当前帧的估计值过程。实在便是将运动矢量参数贴到参考帧上获取当前帧。其余运动补偿是一个过程。
H.264 帧间预测是利用已编码视频帧/场和基于块的运动补偿的预测模式。与以往标准帧间预测的差异在于块尺寸范围更广(从 16×16 到 4×4)、亚像素运动矢量的利用(亮度采取 1/4 像素精度 MV)及多参考帧的利用等等。
每个宏块(16×16 像素)可以 4 种办法分割:一个 16×16,两个 16×8,两个 8×16,四个 8×8。其运动补偿也相应有四种。而 8×8 模式的每个子宏块还可以四种办法分割:一个 8×8,两个 4×8 或两个 8×4 及 4 个 4×4。这些分割和子宏块大大提高了各宏块之间的关联性。这种分割下的运动补偿则称为树状构造运动补偿。
每个分割或子宏块都有一个独立的运动补偿。每个 MV 必须被编码、传输,分割的选择也需编码到压缩比特流中。对大的分割尺寸而言, MV 选择和分割类型只需少量的比特,但运动补偿残差在多细节区域能量将非常高。小尺寸分割运动补偿残差能量低,但须要较多的比特表征 MV 和分割选择。分割尺寸的选择影响了压缩性能。整体而言,大的分割尺寸适宜平坦区域,而小尺寸适宜多细节区域。
宏块的色度身分(Cr 和 Cb)则为相应亮度的一半(水平和垂直各一半)。色度块采取和亮度块同样的分割模式,只是尺寸减半(水平和垂直方向都减半)。例如,8×16 的亮度块相应色度块尺寸为 4×8,8×4 亮度块相应色度块尺寸为 4×2 等等。色度块的 MV 也是通过相应亮度 MV 水平和垂直分量减半而得。
1.3.3、变换和量化绝大多数图像都有一个共同的特色:平坦区域和内容缓慢变革区域霸占一幅图像的大部分,而细节区域和内容突变区域则占小部分。也可以说,图像中直流和低频区占大部分,高频区占小部分。这样,空间域的图像变换到频域或所谓的变换域,会产生干系性很小的一些变换系数,并可对其进行压缩编码,即所谓的变换编码。
此外,为了减小图像编码的动态范围,一样平常也会进行量化。
在图像编码中,变换编码和量化从事理上讲是两个独立的过程。但在 H.264 中,将两个过程中的乘法合二为一,并进一步采取整数运算,减少编解码的运算量,提高图像压缩的实时性。
H.264 对图像或预测残差采取了 4×4 整数离散余弦变换(DCT)技能,避免了以往标准中利用的通用 8×8 离散余弦变 换逆变换常常涌现的失落配问题。量化过程根据图像的动态范围大小确定量化参数,既保留图像必要的细节,又减少码流。
1.3.4、熵编码熵的大小与信源的概率模型有着密切的关系,各个符号涌现的概率不同,信源的熵也不同。当信源中各事宜是等概率分布时,熵具有极大值。信源的熵与其可能达到的最大值之间的差值反响了该信源所含有的冗余度。信源的冗余度越小,即每个符号所独立携带的信息量越大,那么传送相同的信息量所须要的序列长度越短,符号位越少。因此,数据压缩的一个基本的路子是去除信源的符号之间的干系性,尽可能地使序列成为无影象的,即前一符号的涌现不影响往后任何一个符号涌现的概率。
利用信源的统计特性进行码率压缩的编码就称为熵编码,也叫统计编码。熵编码是无损压缩编码方法,它天生的码流可以经解码无失落真地规复出原数据。熵编码是建立在随机过程的统计特性根本上的。
视频编码常用的有两种:变长编码(哈夫曼编码)、算术编码。
H.264 末了将结果进行熵编码,分为高下文自适应的变长编码(Context-based Adaptive Variable-Length Coding,CAVLC)与高下文自适应的二进制算术编码(Context-based Adaptive Binary Arithmetic Coding,CABAC)。
在 H.264 的 CAVLC(基于高下文自适应的可变长编码)中,通过根据已编码句法元素的情形动态调度编码中利用的码表,取得了极高的压缩比。CAVLC 用于亮度和色度残差数据的编码。残差经由变换量化后的数据表现出如下特性:4×4 块数据经由预测、变换、量化后,非零系数紧张集中在低频部分,而高频系数大部分是零;量化后的数据经由 zig-zag 扫描,DC 系数附近的非零系数值较大,而高频位置上的非零系数值大部分是 +1 和 -1;相邻的 4×4 块的非零系数的数目是干系的。CAVLC 充分利用残差经由整数变换、量化后数据的特性进行压缩,进一步减少数据中的冗余信息,为 H.264 卓越的编码效率奠定了根本。
算术编码的思想是用 0 到 1 的区间上的一个数来表示一个字符输入流,它的实质是为全体输入流分配一个码字,而不是给输入流中的每个字符分别指定码字。算术编码是用区间递进的方法来为输入流探求这个码字的,它从于第一个符号确定的初始区间(0 到 1)开始,逐个字符地读入输入流,在每一个新的字符涌现后递归地划分当前区间,划分的根据是各个字符的概率,将当前区间按照各个字符的概率划分成多少子区间,将当前字符对应的子 2 区间取出,作为处理下一个字符时确当前区间。到处理完末了一个字符后,得到了终极区间,在终极区间中任意挑选一个数作为输出。解码器按照和编码相同的方法和步骤事情,不同的是作为逆过程,解码器每划分一个子区间就得到输入流中的一个字符。在实际过程中,输入流中字符的概率分布是动态改变的,这须要掩护一个概率表去记录概率变革的信息。在作递进打算时,通过对概率表中的值估计当前字符的概率,当前字符处理后,须要重新刷新概率表。这个过程表现为对输入流字符的自适应。编码器和解码器按照同样的方法估计和刷新 概率表,从而担保编码后的码流能够顺利解码。
用哈夫曼编码,必须为所有可能的长度为 N 的序列设计和存储码书,这样做的繁芜度随 N 呈指数增长。用算术编码则不须要预先为每个可能的信源序列指定码书。而是每当所确定区间的下限和上限有公共最高有效位时,就可以连续地得到比特。编码序列的长度可以和信源的长度一样长。因此,实际上,算术编码可以更靠近熵率。
算术编码的另一个优点是可以大略地通过更新符号概率表来实现对信源统计特性的自适应。通过对不同高下文用不同的概率表也可以随意马虎地实现条件编码。对付哈夫曼编码,则不得不基于更新的概率表重新设计码书,或对不同的高下文设计多个码表。
由于较高的编码效率和易于自适应,只要所涉及的打算量是能接管的,无疑算术编码比哈夫曼编码是一种更好的选择。
1.4、码流构造1.4.1、原始码流
H.264 原始码流(又称为裸流),是由一个接一个的 NAL 单元组成的(NAL Header 加上 RBSP 组成一个 NAL 单元),构造如下图所示:
在网络传输的环境下,编码器将每个 NAL 各自独立、完全地放入一个分组,由于分组都有头部,解码器可以很方便地检测出 NAL 的分界,依次取出 NAL 进行解码。为了节省码流,H.264 没有其余在 NAL 的头部设立表示起始的句法元素。但是如果编码数据是储存在介质(如 DVD 光盘)上,由于 NAL 是依次紧密排列,解码器将无法在数据流等分辨每个 NAL 的起始和终止,以是必须要有其余的机制来办理这个问题。
针对这个问题,H.264 草案的附录 B 中指明了一种大略又高效的方案。当数据流是存储在介质上时,在每个 NAL 前添加起始码:0x000001。这便是我们常说的 Annex-b 码流格式。
在某些类型的介质上,为了寻址的方便,哀求数据流在长度上对齐,或必须是某个常数的倍数。考虑到这种情形,H.264 建议在起始码前添加多少字节的 0 来添补,直到该 NAL 的长度符合哀求。在这样的机制下,解码器在码流中检测起始码,作为一个 NAL 的起始标识,当检测到下一个起始码时当前 NAL 结束。H.264 规定当检测到 0x00000001 时也可以表征上一个 NAL 的结束,下一个 NAL 开始,这是由于连着的三个字节的 0 中的任何一个字节的 0 要么属于起始码要么是起始码前面添加的 0。
添加起始码是一个办理问题的很好的方法,但上面关于起始码的先容还不完全,由于忽略了一个主要的问题:如果在 NAL 内部涌现了 0x000001 或是 0x00000001 的序列怎么办?毫无疑问这种情形是致命的,解码器将把这些本来不是起始码的字节序列当作起始码,而缺点地认为这里今后是一个新的 NAL 的开始,进而造成解码数据的错位!
而我们做的大量实验证明,NAL 内部常常会涌现这样的字节序列。由于 0x000001 的情形是覆盖 0x00000001 的情形,以是下面值谈论如何处理 0x000001 即可。于是 H.264 提出了其余一种机制,叫做防止竞争,在编码器编码完一个 NAL 时,该当检测是否涌现下表左侧中的四个字节序列,以防止它们和起始码竞争。如果检测到这些序列存在,编码器将在末了一个字节前插入一个新的字节:0x03,从而使它们变成下表右侧的样子。当解码器在 NAL 内部检测到有 0x000003 的序列时,将把 0x03 抛弃,恢复原始数据。
0x000000 → 0x000003000x000001 → 0x000003010x000002 → 0x000003020x000003 → 0x00000303
上表中的前两个序列我们前文中已经提到,第三个 0x000002 是作保留用,而第四个 0x000003是为了担保解码器能正常事情,由于我们刚才提到,解码器恢复原始数据的方法是检测到 0x000003 就抛弃个中的 0x03,这样当涌现原始数据为 0x000003 时会毁坏数据,以是必须也该当给这个序列插入 0x03。
解码器在逐个字节地读一个 NAL 时并不同时对它解码,而是要通过起始码机制将全体 NAL 读进、打算出长度后再开始解码。
到此,我们就知道如何在原始码流里分割 NAL 单元了。接下来,我们再来理解每个 NAL 单元的构造。
1.4.2、NAL 单元NAL 单元由 NAL Header 和 RBSP 构成。
NAL Header 的构造如下:
forbidden_zero_bit,第 0 位,表示禁止位,一样平常为值为 0,值为 1 表示语法缺点。nal_ref_idc,第 1-2 位,表示当前 NAL 的优先级。取值范围为 0-3,值越高,表示当前 NAL 越主要,须要优先受到保护。H.264 规定如果当前 NAL 是属于参考帧的片,或是序列参数集,或是图像参数集这些主要的数据单位时,本句法元素必须大于 0。但在大于 0 时详细该取何值,却没有进一步规定,通信双方可以灵巧地制订策略。nal_unit_type,第 3-7 位,表示当前 NAL 单元的类型。详细类型定义如下表:
nal_unit_type=5 时,表示当前 NAL 是 IDR 图像的一个片,在这种情形下,IDR 图像中的每个片的 nal_unit_type 都该当即是 5。把稳 IDR 图像不能利用片分区。
1.4.3、RBSP前面也先容过,RBSP 指原始字节载荷,它是 NAL 单元的数据部分的封装格式,封装的数据来自 SODB(原始数据比特流)。SODB 是编码后的原始数据,SODB 经封装为 RBSP 后放入 NAL 的数据部分。
从 SODB 到 RBSP 的天生过程:
如果 SODB 内容是空的,天生的 RBSP 也是空的。否则,RBSP 由如下的办法天生:1)RBSP 的第一个字节直接取自 SODB 的第 1-8 个比特,(RBSP 字节内的比特按照从左到右对应为从高到低的顺序排列,most significant),以此类推,RBSP 别的的每个字节都直接取自 SODB 的相应比特。RBSP 的末了一个字节包含 SODB 的末了几个比特和 rbsp_trailing_bits()。2)rbsp_trailing_bits() 的第一个比特是 1,接下来添补 0,直到字节对齐。3)末了添加多少个 cabac_zero_word,其值即是 0x0000。1.4.4、NAL 单元的不同类型上面讲到了 NAL 单元是有多种类型的,这里我们就个中主要的几种类型做一下讲解:
SPSPPSSEISlice序列参数集、图像参数集与图像、片之间的关系:
1)序列参数集 SPS
SPS 中保存了一组编码后的图像序列的依赖的全局参数。
SPS 中的信息至关主要,如果个中的数据丢失,解码过程就可能失落败。SPS 和 PPS 常日作为解码器的初始化参数。一样平常情形,SPS 和 PPS 所在的 NAL 单元位于全体码流的起始位置,但是在某些场景下,在码率中间也可能涌现这两种构造:
解码器要在码流中间开始解码。比如,直播流。编码器在编码过程中改变了码率的参数。比如,图像的分辨率。SPS 个中的关键参数包括:
profile_idc: 表示当前 H.264 码流的编码档次。个中部分档次:根本档次:BaselineProfile (profile_idc 值为 66)紧张档次:MainProfile (profile_idc 值为 77)扩展档次:ExtentedProfile (profile_idc 值为 88)level_idc,表示当前码流的编码等级。编码的等级定义了某种条件下的最大视频分辨率、最大视频帧率等参数。seq_parameter_set_id,表示当前的序列参数集的 id。通过该 id 值,图像参数集 PPS 可以引用其关联的 SPS 中的参数。log2_max_frame_num_minus4,用于打算 MaxFrameNum 的值。打算公式为 MaxFrameNum = 2 ^ (log2_max_frame_num_minus4 + 4)。变量 MaxFrameNum 表示 frame_num 的最大值,frame_num 标识所属图像的解码顺序,在解码过程中它也是一个非常主要的变量。值得把稳的是 frame_num 是循环计数的,即当它到达 MaxFrameNum 后又从 0 重新开始新一轮的计数。解码器必须要有机制检测这种循环,不然会引起类似千年虫的问题,在图像的顺序上造成混乱。pic_order_cnt_type,指明了 POC(Picture Order Count) 的编码方法,POC 标识图像的播放顺序。由于 H.264 利用了 B 帧预测,使得图像的解码顺序并不一定即是播放顺序,但它们之间存在一定的映射关系。POC 可以由 frame-num 通过映射关系打算得来,也可以索性由编码器显式地传送。H.264 中一共定义了三种 POC 的编码方法,这个句法元素便是用来关照解码器该用哪种方法来打算 POC。log2_max_pic_order_cnt_lsb_minus4,用于打算 MaxPicOrderCntLsb 的值。打算公式为 MaxPicOrderCntLsb = 2 ^ (log2_max_pic_order_cnt_lsb_minus4 + 4)。MaxPicOrderCntLsb 表示 POC 的最大值,该变量在 pic_order_cnt_type = 0 时利用。num_ref_frames,指定参考帧行列步队可能达到的最大长度,解码器依照这个句法元素的值开辟存储区,这个存储区用于存放已解码的参考帧,H.264 规定最多可用 16 个参考帧,本句法元素的值最大为 16。值得把稳的是这个长度以帧为单位,如果在场模式下,该当相应地扩展一倍。gaps_in_frame_num_value_allowed_flag,这个句法元素即是 1 时,表示许可句法元素 frame_num 可以不连续。当传输信道堵塞严重时,编码器来不及将编码后的图像全部发出,这时许可丢弃多少帧图像。在正常情形下每一帧图像都有依次连续的 frame_num 值,解码器检讨到如果 frame_num 不连续,便能确定有图像被编码器丢弃。这时,解码器必须启动缺点掩蔽的机制来近似地规复这些图像,由于这些图像有可能被后续图像用作参考帧。当这个句法元素即是 0 时,表不许可 frame_num 不连续,即编码器在任何情形下都不能丢弃图像。这时,H.264 许可解码器可以不去检讨 frame_num 的连续性以减少打算量。这种情形下如果依然发生 frame_num 不连续,表示在传输中发生丢包,解码器会通过其他机制检测到丢包的发生,然后启动缺点掩蔽的规复图像。pic_width_in_mbs_minus1,本句法元素加 1 后指明图像宽度,以宏块为单位:frame_width = 16 (pic_width_in_mbs_minus1 + 1),宏块尺寸是 16x16。通过这个句法元素解码器可以打算得到亮度分量以像素为单位的图像宽度:PicWidthInSamplesL = PicWidthInMbs 16,从而也可以得到色度分量以像素为单位的图像宽度:PicWidthInSamplesC = PicWidthInMbs 8。以上变量 PicWidthInSamplesL、PicWidthInSamplesC 分别表示图像的亮度、色度分量以像素为单位的宽。H.264 将图像的大小在 SPS 中定义,意味着可以在通信过程中随着 SPS 动态地改变图像的大小,乃至可以将传送的图像剪裁后输出。pic_height_in_map_units_minus1,本句法元素加 1 后指明图像高度:PicHeightInMapUnits = pic_height_in_map_units_minus1 + 1,PicSizeInMapUnits = PicWidthInMbs PicHeightInMapUnits。图像的高度的打算要比宽度的打算繁芜,由于一个图像可以是帧也可以是场,从这个句法元素可以在帧模式和场模式下分别打算出出亮度、色度的高。值得把稳的是,这里以 map_unit 为单位。frame_mbs_only_flag,本句法元素即是 0 时表示本序列中所有图像的编码模式都是帧,没有其他编码模式存在;本句法元素即是 1 时 ,表示本序列中图像的编码模式可能是帧,也可能是场或帧场自适应,某个图像详细是哪一种要由其他句法元素决定。结合 map_unit 的含义,这里给出上一个句法元素 pic_height_in_map_units_minus1 的进一步解析步骤:当 frame_mbs_only_flag 即是 1,pic_height_in_map_units_minus1 指的是一个 picture 中帧的高度;当 frame_mbs_only_flag 即是 0,pic_height_in_map_units_minus1 指的是一个 picture 中场的高度。以是可以得到如下以宏块为单位的图像高度:FrameHeightInMbs = ( 2 – frame_mbs_only_flag ) PicHeightInMapUnits。PictureHeightInMbs= ( 2 – frame_mbs_only_flag ) PicHeightInMapUnits。2)图像参数集 PPS
PPS 中保存了每一帧编码后的图像所依赖的参数。
PPS 个中的关键参数包括:
pic_parameter_set_id,表示当前 PPS 的 id,干系联的各片通过这个 id 来引用对应的 PPS 参数。seq_parameter_set_id,表示当前 PPS 引用的 SPS 的 id。entropy_coding_mode_flag,表示熵编码的选择,本句法元素为 0 时,表示熵编码利用 CAVLC,本句法元素为 1 时表示熵编码利用 CABAC。pic_order_present_flag,POC 的三种打算方法在片层还各须要用一些句法元素作为参数,本句法元素即是 1 时表示在片头会有句法元素表示这些参数;本句法元素即是 0 时,表示片头不会给出这些参数,这些参数利用默认值。num_slice_groups_minus1,本句法元素加 1 后表示图像中片组的个数。H.264 中没有专门的句法元素用于表示是否利用片组模式,当本句法元素即是 0 (即只有一个片组),表示不该用片组模式,后面也不会跟有用于打算片组映射的句法元素。slice_group_map_type,当 num_slice_group_minus1 大于 0,即利用片组模式时,本句法元素涌如今码流中,用以表示片组分割类型。map_units 的定义:帧场自适应模式时,map_units 指的是宏块对;场模式时,map_units 指的是宏块;帧模式时,map_units 指的是与宏块对相类似的,高下两个连续宏块的组合体。当 frame_mbs_only_flag 即是 1 时,map_units 指的便是宏块;当 frame_mbs_only_falg 即是 0 时:num_ref_idx_l0_active_minus1,加 1 后表示目前参考帧行列步队的长度,即有多少个参考帧(包括短期和长期)。值得把稳的是,当目前解码图像是场模式下,参考帧行列步队的长度该当是本句法元素再乘以 2,由于场模式下各帧必须被分解以场对形式存在。(这里所说的场模式包括图像的场及帧场自适应下的处于场模式的宏块对) 本句法元素的值有可能在片头被重载。在序列参数集中有句法元素 num_ref_frames 也是跟参考帧行列步队有关,它们的差异是 num_ref_frames 表示参考帧行列步队的最大值,解码器用它的值来分配内存空间;num_ref_idx_l0_active_minus1 表示在这个行列步队中当前实际的、已存在的参考帧数目,这从它的名字 active 中也可以看出来。这个句法元素是 H.264 中最主要的句法元素之一,编码器要关照解码器某个运动矢量所指向的是哪个参考图像时,并不是直接传送该图像的编号,而是传送该图像在参考帧行列步队中的序号。这个序号并不是在码流中传送的,而是编码器和解码器同步地、用相同的方法将参考图像放入行列步队,从而得到一个序号。这个行列步队在每解一个图像,乃至是每个片后都会动态地更新。掩护参考帧行列步队是编解码器十分主要的事情,而本句法元素是掩护参考帧行列步队的主要依据。参考帧行列步队的繁芜的掩护机制是 H.264 主要也是很有特色的组成部分。num_ref_idx_l1_active_minus1 与上一个句法元素的语义同等,只是本句法元素用于 list1,而上一句法元素用于 list0。constrained_intra_pred_flag,在 P 和 B 片中,帧内编码的宏块的临近宏块可能是采取的帧间编码。当本句法元素即是 1 时,表示帧内编码的宏块不能用帧间编码的宏块的像素作为自己的预测,即帧内编码的宏块只能用临近帧内编码的宏块的像素作为自己的预测;而本句法元素即是 0 时,表示不存在这种限定。3)补充增强信息 SEI
SEI 即补充增强信息(Supplemental Enhancement Information),属于码流范畴,它供应了向视频码流中加入额外信息的方法,是 H.264 标准的特性之一。
SEI的基本特色如下:
并非解码过程的必须选项;可能对解码过程(容错、纠错)有帮助;集成在视频码流中。也便是说,视频编码器在输出视频码流的时候,可以不供应 SEI 信息。虽然在视频的传输过程、解封装、解码这些环节,都可能由于某种缘故原由丢弃 SEI 内容,但在视频内容的天生端和传输过程中,是可以插入 SEI 信息的。这些插入的信息,和其他视频内容一同经由传输链路到达消费端。
SEI 是一种 NAL 单元类型。它的构造大致如下:
// H.2640x06,n 个 FF 字节 + 1 个非 FF 字节,16 字节 UUID,userData,0x80 或 0x0080
开始码:H.264 中 SEI 的 NAL 单元类型是 0x06;H.264 中 SEI 的 NAL 单元类型是 0x4E、0x01。自定义:SEI 除了开始的 NAL 单元类型字段外,还存在不同的子类型。H.264 中第 2 个字节或者 H.265 中第 3 个字节 0x05 表示后续是自定义数据。负载长度:表示后续随着的自定义数据长度,打算方法是:n 255 + XY,也便是将数据长度减去 255,有多少个就写多少个 FF,剩下的如果不为 0,再写一个字节。负载内容:负载内容是 UUID + payload content。UUID 固定 16 个字节,用于区分不同的业务。payload content 表示自定义数据。4)片 Slice
一帧图像可编码成一个或者多个片,每片包含整数个宏块,分片的目的是为了限定缺点码的扩散和传输,使编码片相互间保持独立。
片的构造:
Slice 中的关键参数包括:
slice_type,表示当前片的类型。详细类型如下。个中,IDR 图像时,slice_type 即是 2、4、7、9。pic_parameter_set_id,表示引用的 PPS 的 id。frame_num,表示解码顺序。每个参考帧都有一个依次连续的 frame_num 作为它们的标识,这指明了各图像的解码顺序。但事实上非参考帧的片头也会涌现 frame_num。只是当该个图像是参考帧时,它所携带的这个句法元素在解码时才故意义。H.264 对 frame_num 的值作了如下规定:当参数集中的句法元素 gaps_in_frame_num_value_allowed_flag 不为 1 时,每个图像的 frame_num 值是它前一个参考帧的 frame_num 值增加 1。field_pic_flag,这是在片层标识图像编码模式的唯一一个句法元素。所谓的编码模式是指的帧编码、场编码、帧场自适应编码。idr_pic_id,IDR 图像的标识。不同的 IDR 图像有不同的 idr_pic_id 值。值得把稳的是,IDR 图像有不等价于 I 图像,只有在作为 IDR 图像的 I 帧才有这个句法元素,在场模式下,IDR 帧的两个场有相同的 idr_pic_id 值。idr_pic_id 的取值范围是 [0,65535],和 frame_num 类似,当它的值超出这个范围时,它会以循环的办法重新开始计数。pic_order_cnt_lsb,在 POC 的第一种算法中本句法元向来打算 POC 值,在 POC 的第一种算法中是显式地通报 POC 的值,而其他两种算法是通过 frame_num 来映射 POC 的值。