音视频入门(一)编码和H.264编码概述

1,968 阅读10分钟

一. 视频文件

1.1 视频文件和播放

视频文件可被感知的有两个方面:视频音频,一个完整的视频文件中,可能包含着不同场景的多个子视频,不同的多个子音频。

我们将这些视频码流音频码流进行封装格式数据,形成我们常见的MP4、MKV、AVI文件,就可以在网络上进行传输了。

当我们拿到一个视频文件时,我们可以通过支持该格式的视频播放软件进行播放,播放主要包括如下步骤:

  1. 解封装 : 分别得到压缩后的音频数据和视频数据。常见的音频压缩数据包括:AAC、MP3等等,而视频则包括H.264、MPEG等等。
  2. 解码 :调用解码器对音视频分别解码,得到相应的采样数据:音频采样数据(PCM),视频像素数据(YUV)。
  3. 音视频同步
  4. 播放:通过显示器、音响进行播放。

二. 编码

2.1 为什么要编码?

在文件编码这块主要由两个目的,其一是形成统一的数据形式,以便于存储和传输,第二是为了删除冗余数据

试想一下,一个1080P 30帧,32bit色彩 时长为1秒的视频文件,如果按每一帧画面进行存储的话,数据大小将会达到:

32bit * 30 * 1080 * 1920 ≈ 237MB的空间,除非有特殊的需求,这种方式存储、传输视频显然是不可接受的。

如果我们采取编码算法,例如MPEG4、H.264等等算法对视频文件进行去冗余,压缩后,那么实际上得到的文件大小会大大降低。

2.2. 数据冗余

前面说到,编码的主要目的是为了压缩,各种编码方式都是为了让视频体积小,核心的思想就是:去除冗余信息,冗余信息主要包括:

1. 空间冗余:图像内部相邻像素之间存在较强的相关性造成的冗余。

空间冗余.png 例如这样一张视频截图,在背景色全部是黑色的情况下,我们实际上没有必要按照视频大小(1124*772)存储黑色,我们可以将存储黑色的像素点抽离出来记录,只存储其他像素点的颜色即可。

2. 时间冗余:视频图像序列中不同帧之间的相关性造成的冗余

时间.png

简单地说就是帧A和帧B是前后帧的关系,并且两个帧之间画面变化相对较小,那么帧B就完全没有必要存储一个完整的画面帧,记录变化即可。

3. 视觉冗余

人眼难以感知到或者说不敏感的部分图像数据可以压缩存储。

例如,对于图像的编码和解码处理时,由于压缩或量比截断引入了噪声而使图像发生了一些变化,如果这些变化不能为视觉所感知,则仍认为图像足够好。

事实上人类视觉系统一般的分辨能力约为26灰度等级,而一般图像量化采用28灰度等级,这类冗余我们称为视觉冗余。

4. 信息熵冗余

也称编码冗余,人们用于表达某一信息所需要的比特位数比理论上表示该信息所需要的最小比特数来的大,这之间的差距就成为信息熵冗余。

熵编码: 哈夫曼算法:表示 111122222可以表示成:4152,九个bit的数据用4个bit即可表示。

5. 知识冗余

有些图像中包含某些验证知识有关的信息。

2.3. 如何编码

视频压缩中,引入了一个新的概念IPB帧,上文说到了,一些变化不大的画面可以只记录变化部分的数据,在解码时通过一个完整帧 + 变化部分的数据来实现解码。 我们将帧区分为三种:

  1. I帧:关键帧,一帧画面的完整保留;解码时只需要本帧数据就可以完成。
  2. P帧:差别帧,这一帧跟之前的一个关键帧(或P帧)的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。
  3. B帧:双向差别帧,本帧与前后帧的差别。要解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率相对来说最高。B帧主要通过比对前帧和后帧的数据差值来进行压缩本帧。涉及到前后站的对比,所以B帧对CPU的使用也是最高的。

IBP.png 总的来说就是,I帧压缩率最低,因为它需要最原始的画面数据。P帧则只需要I帧(或者是一个P帧) + 变化的数据即可,而B帧则需要:前一个I帧或P帧及后面的一个P帧来生成一个完整的视频画面。

从冗余种类上那个来说:

  • I帧去掉的是空间、视觉、信息熵维度上的冗余信息。
  • P帧、B帧则是去除掉时间上的冗余信息。所以他们都依赖于I帧。

在MPEG4编码的视频文件中,我们在得到某一帧后,其固定的开头都是:00 00 01 b6,然后在接下来的两bit,我们可以得到其IBP帧的分类:

  • 00:I 帧
  • 01:P 帧
  • 10:B 帧

三. H.264简介

H.264是目前主流的码流格式,主要的特性是:高质量的图像高压缩比良好的网络亲和性。H.264是在MPEG-4技术上建立起来的,编码流程主要包括:

  1. 帧间
  2. 帧内预测
  3. 变换、反变换
  4. 量化、反量化
  5. 环路滤波
  6. 熵编码

具体的内容暂时不做展开。但是我们需要明确一下,H.264、MPEG和MP4、AVI的区别,实际上,MPEG和H.264是我们的原始视频经过压缩后得到的视频流信息,进一步封包即可得到我们的MP4等具体的视频文件,H.264是一种编码标准,而MP4则是一种封装

3.1 层次

H.264码流文件分为两层:

  1. VCL(Video Coding Layer)即视频编码层,负责高效的视频内容表示,VCL数据即编码处理的输出,它表示被压缩后的视频的数据序列。
  2. NAL(Network Abstraction Layer)即网络提取层, 负责以网络所要求的,恰当的方式对数据进行打包和传送,是传输层,不论在本地播放,还是网络播放,都要通过这一层来进行传输。

实际上这两“层”,层的概念和计算机网络层的概念是一样的,即一段视频,我们经过VCL编码,再进过NAL层打包,就可以得到一个封装后的HTTP报文,即可在TCP链路上进行传输,到端后同层进行解包、解码就可以得到原有的视频。

我们在编程中,数据会被组织成JavaBean,JavaBean想要在网络中传输也要序列化,然后TCP传输,到端后进行反序列化提取出JavaBean。

需要注意的是:

  1. 一个NAL单元就是一个Slice(片),而一帧不一定就是一个NAL单元,一帧里面可能会有多个NAL单元(多个片)。

3.2 片和宏块

一帧的图片,经过H.264编码器之后,就被编码成一个或者多个片(Slice),每片包含整数个宏块(至少一个),而NAL单元,就是装载着这些宏块的载体。

片.png 如图,被白色的横线划分成为了五个横向区域,其中的一个区域就是一个“片(Slice)”,片中,又像第二行中白色的细线一样(偷懒没画完)划分成一个个的宏块。而NAL层,就是装载不同的“片”(片中包含宏块)的。

3.3 Annexb 格式

一般的H.264编码器的默认输出为:起始码 + NALU(NAL Unit,即NAL单元),起始码为:0x00000001或者0x000001。

起始码之后的第一个字节信息,是一个NAL Header信息。(一个字节8bit,按十六进制数是2位)在这8bit中的低五位,表示NAL U的类型。例如:(HEX:67)0110 0111,则00111表示的是当前NAL单元的信息。

起始码1.png 五个二进制位,共同可以表示32种不同的NAL单元。

NALU 构成.png

关于视频的文件的元数据,都在H264的开头的三个NAL单元中给出了,所以你会看到上图中,第四个NAL单元开始,StartCode基本上都是0000000141,而前三个则不相同,分别是:67(Hex)->01100111(Bin) -> 00111,即7,在NAL的type对应表中,我们可以看到,7对应的类型是:序列参数集。同理我们可得68对应的是:图像参数集

值得注意的是第三个,65,对应的类型是:5,即IDR图像的编码条带,听起来很陌生,其实就是我们上文提到的:关键帧(I帧)。我们要注意的是,在序列参数集图像参数集后一定会紧跟一个I帧。

为啥?因为只有关键帧才能独立解码,后面的P帧依赖于其前的关键帧。

而41(Hex)对应的类型则是:1,即:一个非IDR图像的编码条带,也就是我们所说的P帧(其后也标注了P Slice)。其实从各自的Length中也能看出一些端倪,I帧的Length较长,P帧的Length较短,因为I帧作为关键帧需要保留完整的解码一帧的足够数据,所以自然而然就需要更多的描述信息,而P帧只需要记录下变化,因此P帧自然会更短。

3.4 H264转换实践与查看

首先,如果没有H.264文件的话,我们需要借助一个工具:FFmpeg,这个工具我们可以再FFmpeg的官方网站中下载。如果有H264文件就不必了,直接进行下一步。

其次,我们需要找个视频,我个人是在音乐软件上下载的MV。

然后下载一个工具:BSAnalyser,这个主要是用于解析H264文件的。这个文件在Github上面可以搜索到,但是网速很慢,可以在码云的镜像网站中下载:

都完成之后,我们为FFmpeg目录下的Bin文件配置Path路径,完成后,对视频,在CMD中做如下操作:

ffmpeg -i cp.mp4 -vcodec h264 -preset fast -b:v 2000k hello.h264

其中,cp.mp4是我们的视频文件,而hello.h264是我们输出的H264文件,当然如果你手头上有H.264文件就不需要这么麻烦了。

我们将生成的hello.h264拖入到BSAnalyser,即有:

H264分析.png

3.5. H264与MPEG视频编码规范

比较重要的编解码标准有:国际电信联盟(ITU-T)的H.261、H.263、H.264等等,运动静止图像专家组(由ISO国际标准化组织与IEC国际电子委员会于1988年联合成立)的MPEG系列标准MPEG1、MPEG2、MPEG4 AVC等等。

其中,ITU-T H.264/MPEG-4 AVC是ITU-T与ISO/IEC联手合作定制的新标准,ITU-T方面称之为:H.264,但ISO/IEC的则将这个新标准归纳于MPEG系列,称之为MPEG-4 AVC

而H.265则被称为是ITU-T H.264/MPEG-4 AVC标准的继任者,又称为高效率视频编码(High Efficiency Video Coding,即HEVC)。

虽然更新的H265已经推出了,但是目前的主流的视频基本上都还是H264编码的。