iOS RTMP 视频直播开发笔记(3)- 了解 H.264 编码

本节内容整理自:H264–1–编码原理以及I帧B帧P帧,作者:dxpqxb

H264是一种高压缩率的编码标准,如何压缩嘞?一般的视频采集都是25帧/秒,也就是每秒截图25次,其实每一张图片的内容都相差不大,压缩的办法就是利用算法,只将每张图片变动差异化的部分保存下来,这样视频文件就小多了。

三种帧

在H264协议里定义了三种帧,完整编码的帧叫I帧,参考之前的I帧生成的只包含差异部分编码的帧叫P帧,还有一种参考前后的帧编码的帧叫B帧

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

I帧:帧内编码帧 ,I帧表示关键帧,你可以理解为这一帧画面的完整保留;解码时只需要本帧数据就可以完成(因为包含完整画面)

P帧:前向预测编码帧。P帧表示的是这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(也就是差别帧,P帧没有完整画面数据,只有与前一帧的画面差别的数据)

B帧:双向预测内插编码帧。B帧是双向差别帧,也就是B帧记录的是本帧与前后帧的差别(具体比较复杂,有4种情况,但我这样说简单些),换言之,要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累。

序列的概念

在H264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流,以I帧开始,到下一个I帧结束

一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。

一个序列就是一段内容差异不太大的图像编码后生成的一串数据流。当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以编一个I帧,然后一直P帧、B帧了。当运动变化多时,可能一个序列就比较短了,比如就包含一个I帧和3、4个P帧。

片、场、帧、片的概念

H264结构中,一个视频图像编码后的数据叫做一帧,一帧由一个片(slice)或多个片组成,一个片由一个或多个宏块(MB)组成,一个宏块由16×16的yuv数据组成。宏块作为H264编码的基本单位。

1帧 = n个片
1片 = n个宏块
1宏块 = 16x16yuv数据

场和帧:视频的一场或一帧可用来产生一个编码图像。在电视中,为减少大面积闪烁现象,把一帧分成两个隔行的场。

宏块:一个编码图像通常划分成若干宏块组成,一个宏块由一个16×16亮度像素和附加的一个8×8 Cb和一个8×8 Cr彩色像素块组成。

片:每个图象中,若干宏块被排列成片的形式。片分为I片、B片、P片和其他一些片。

  • I片只包含I宏块,P片可包含P和I宏块,而B片可包含B和I宏块。
  • I宏块利用从当前片中已解码的像素作为参考进行帧内预测。
  • P宏块利用前面已编码图象作为参考图象进行帧内预测。
  • B宏块则利用双向的参考图象(前一帧和后一帧)进行帧内预测。

数据结构

H264编码后的数据分为两层

  1. VCL(video coding layer)视频编码层:它是对核心算法引擎,块,宏块及片的语法级别的定义,最终输出编码完的数据 SODB。
  2. NAL(network abstraction layer)网络提取层:定义片级以上的语法级别(如序列参数集和图像参数集,针对网络传输),同时支持以下功能:独立片解码,起始码唯一保证,SEI以及流格式编码数据传送,NAL层将SODB打包成RBSP然后加上NAL头,组成一个NALU(NAL单元)。

分层的好处显而易见,对于RTMP传输数据,我们只需了解NAL层就足够了。

H264在网络传输的是NALU,NALU的结构是:NAL头+RBSP,如图所示:

从前面的分析我们知道,VCL层出来的是编码完的视频帧数据,这些帧可能是I、B、P帧,而且这些帧可能属于不同的序列,再者同一个序列还有相对应的一套序列参数集和图片参数集等等,所以要完成视频的解码,不仅需要传输VCL层编码出来的视频帧数据,还需要传输序列参数集图像参数集等数据。

NALU头用来标识后面的RBSP是什么类型的数据,他是否会被其他帧参考以及网络传输是否有错误。

RBSP用来存放下表中的一种:

RBSP类型 所写 描述
参数集 PS 序列的全局信息,如图像尺寸,视频格式等
增强信息 SEI 视频序列解码的增强信息
图像界定符 PD 视频图像的边界
编码片 SLICE 编码片的头信息和数据
数据分割 DP 片层的数据,用于错误恢复解码
序列结束符 表明一个序列的结束,下一个图像为IDR图像
流结束符 表明该流中已没有图像
填充数据 亚元数据,用于填充字节

其中参数集包括:序列参数集 SPS图像参数集 PPS

  • SPS 包含的是针对一连续编码视频序列的参数,如标识符 seq_parameter_set_id、帧数及 POC 的约束、参考帧数目、解码图像尺寸和帧场编码模式选择标识等等。
  • PPS 对应的是一个序列中某一幅图像或者某几幅图像,其参数如标识符 pic_parameter_set_id、可选的 seq_parameter_set_id、熵编码模式选择标识、片组数目、初始量化参数和去方块滤波系数调整标识等等。

这里 SPS 和 PPS 的含义可以不用深入追究,需要明白的是,在视频发送时,这两个参数需要作为第一帧发送出去,这样后边的I、B、P 帧才能顺利解码播放。

数据分割:组成片的编码数据存放在 3 个独立的 DP(数据分割,A、B、C)中,各自包含一个编码片的子集。分割A包含片头和片中每个宏块头数据。分割B包含帧内和 SI 片宏块的编码残差数据。分割 C包含帧间宏块的编码残差数据。每个分割可放在独立的 NAL 单元并独立传输。(这个还没搞明白,先知道有这么回事)

转载自 Tony's blog

你可能感兴趣的:(iOS RTMP 视频直播开发笔记(3)- 了解 H.264 编码)