视频文件就相当于是:音频码流和视频码流结合封装的一个容器。其中一个视频文件中可以放入多个音频码流和视频码流的文件。
并且从视频文件中导出来的视频压缩数据是不可以直接进行播放的(假设里面有两张相似的图片,其实并没有保存两张图片的完整信息,第二张图片可能只保存了与第一张图片的不同信息)
视频是连续的图像序列,由连续的帧构成,一帧即为一幅图像。由于人眼的视觉暂留效应,当帧序列以一定的速率播放时,我们看到的就是动作连续的视频。这么多连续的图像数据如果不经过编码的数据量太大了。
比如一个1920x1080分辨率,32位,每秒30帧的视频,一秒钟需要1920+1080+32*30,大小大概为237M数据。
所以编码说白了就是压缩数据!!!!!
之前有提到两张相似图片没必要保存他的两张图片的全部信息,那他们是怎么样保存的呢?
- l帧 :帧内编码帧,关键帧,l帧可以看作一个图像经过压缩之后的产物,可以单独解码出一个完整的图像;
- P帧 :前向预测编码帧,记录了本帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。
- B帧 :双向预测编码帧,记录了本帧与前后帧的差别,解码需要参考前面一个l帧或者P帧,同时也需要后面的P帧才能解码一张完整的图像。
GOP(序列):
编码器将多张图像进行编码后生产成一段一段的 GOP ( Group of Pictures ) , 解码器在播放时则是读取一段一段的 GOP 进行解码后读取画面再渲染显示。
在视频编码序列中,GOP即Group of picture(图像组),指两个I帧之间的距离,Reference(参考周期)指两个P帧之间的距离。两个I帧之间形成一组图片,就是GOP(Group Of Picture)。
IDR:
在H.264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流。一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。
IDR的工作原理
H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。
如果前一个序列出现重大错误,在这里可以获得重新同步的机会。
IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。
DTS(Decoding Time Stamp):即解码时间戳,这个时间戳的意义在于告诉播放器该在什么时候解码这一帧的数据。
PTS(Presentation Time Stamp):即显示时间戳,这个时间戳用来告诉播放器该在什么时候显示这一帧的数据。
引入此概念的原因:
通过上面的描述可以看出:P帧需要参考前面的I帧或P帧才可以生成一张完整的图片,而B帧则需要参考前面I帧或P帧及其后面的一个P帧才可以生成一张完整的图片。
这样就带来了一个问题:在视频流中,先到来的 B 帧无法立即解码,需要等待它依赖的后面的 I、P 帧先解码完成,这样一来播放时间与解码时间不一致了,顺序打乱了,那这些帧该如何播放呢?这时就引入了另外两个概念:DTS 和 PTS。
虽然 DTS、PTS 是用于指导播放端的行为,但它们是在编码的时候由编码器生成的。
在视频采集的时候是录制一帧就编码一帧发送一帧的,在编码的时候会生成 PTS,这里需要特别注意的是 frame(帧)的编码方式,在通常的场景中,编解码器编码一个 I 帧,然后向后跳过几个帧,用编码 I 帧作为基准帧对一个未来 P 帧进行编码,然后跳回到 I 帧之后的下一个帧。编码的 I 帧和 P 帧之间的帧被编码为 B 帧。之后,编码器会再次跳过几个帧,使用第一个 P 帧作为基准帧编码另外一个 P 帧,然后再次跳回,用 B 帧填充显示序列中的空隙。这个过程不断继续,每 12 到 15 个 P 帧和 B 帧内插入一个新的 I 帧。P 帧由前一个 I 帧或 P 帧图像来预测,而 B 帧由前后的两个 P 帧或一个 I 帧和一个 P 帧来预测,因而编解码和帧的显示顺序有所不同,如下所示:
另外,并不是一定要使用B帧。在实时互动直播系统中,很少使用B帧。主要的原因是压缩和解码B帧时,由于要双向参考,所以它需要缓冲更多的数据,且使用的CPU也会更高。由于实时性的要求,所以一般不使用它。不过对于播放器来说,遇到带有B帧的H264数据是常有的事儿。在没有B帧的情况下,存放帧的顺序和显示帧的顺序就是一样的,PTS和DTS的值也是一样的。
编码的目的,就是为了压缩。各种视频编码方式,都是为了让视频变得体积更小,有利于存储和传输。编码的核心思想就是去除冗余信息。
冗余的类型:
- 空间冗余:图像内部相邻像素之间存在较强的相关性多造成的冗余。
- 时间冗余:视频图像序列中的不同帧之间的相关性所造成的冗余。
- 视觉冗余:是指人眼不能感知或不敏感的那部分图像信息。
- 信息嫡冗余:也称编码冗余,人们用于表达某一信息所需要的比特数总比理论上表示该信息所需要的最少比特数要大,它们之间的差距就是信息嫡冗余,或称编码冗余。(类似于一串数据是11112222八个数据,就可以使用4142共4个数据来表示)
- 知识冗余:是指在有些图像中还包含与某些验证知识有关的信息。
- .........
所谓视频编码就是指通过特定的压缩技术,将某个视频格式文件转换成另一种视频格式文件的方式。视频流传输中最重要的编解码标准有国际电联(ITU-T,国际电信联盟)的H.261、H.263、H.264等,运动静止图像专家组(由ISO国际标准化组织与IEC国际电子委员会于1988年联合成立)的MPEG系列标准MPEG1、MPEG2、MPEG4 AVC等。
其中ITU-TH.264/MPEG-4 AVC是ITU-T与ISO/IEC连手合作制订的新标准。ITU-T方面称之为H.264。但ISO/IEC的则将这个新标准归纳于MPEG系列,称为MPEG-4 AVC。
而H.265则被视为是ITU-TH.264/MPEG-4 AVC标准的继任者,又称为高效率视频编码(High Efficiency VideoCoding,简称HEVC) 。
H.264码流文件分为两层:
- VCL (Video Coding Layer,视频编码层)︰负责高效的视频内容表示,VCL数据即编码处理的输出,它表示被压缩编码后的视频数据序列。
- NAL (Network Abstraction Layer,网络提取层)︰负责以网络所要求的恰当的方式对数据进行打包和传送,是传输层。不管在本地播放还是网络播放,都要通过这一层来传输。
VCL就是被压缩编码后原始数据,在VCL数据封装到NAL单元中之后,才可以用于传输或存储。
一帧图片经过H.264编码器之后,就被编码为一个或多个片(slice),每片包含整数个宏块(至少一个宏块,最多包含整个图像宏块),NAL单元就是装载着这些片(slice)的载体。
一般H.264编码器的默认输出为︰起始码+NALU (Nal单元)。起始码为:0x00000001或者0x000001(起始码的作用:用来划分单元 ,类似于文章的标点符号)。每个NALU包含1个字节的Nal Header与若干整数字节的负荷数据EBSP构成。
NALU的结构如下:
其中Nal Header占用1个字节,此字节低5位表示NALU类型:
我们知道了Nal Header底五位表示了NALU的类型,接下来我们来看一下整体的文件是怎么样的。
在.h264文件的开头处第一个和第二个必然是SPS类型(底五位为7:序列参数集)和PPS类型(底五位为8:图像参数集)。
这两个里面保存了一些视频文件的基本信息:比如说分辨率,解码的规则,视频的帧率和码率等等。
第一个和第二个结束之后必然跟了一个关键帧:因为只有关键帧才可以独立解码。