视频直播知识之一:数据的采集和编码

前言

笔者打算从零开始学习视频直播的知识,借此记录下学习路线。
首先,一个完整的直播流程主要包括:

  1. 数据的采集和编码(在采集端采集、滤镜等处理、编码)
  2. 推流、拉流和服务端处理(推流、拉流用到的流媒体传输协议,在服务器端进行转码、安全检测、CDN分发)
  3. 播放端播放(拉流后播放端解码和渲染)

视频直播框架
这篇文章主要记录在推流端视频的采集、滤镜等处理、编码相关的知识。

同系列文章:

  1. 视频直播知识之一:数据的采集和编码
  2. 视频直播知识之二:推流、拉流和服务端处理
  3. 视频直播知识之三:播放端播放
  4. 视频直播知识之四:直播DEMO——RTMP推流和HTTP-FLV拉流

1 数据采集

采集,是视频直播开始的第一个环节,用户可以通过不同的终端采集视频。
视频的采集过程主要由摄像头等设备拍摄成YUV或其他编码的原始数据。原始视频的格式常见的有YUV(YUV420,YUV422,YUV444等)。
音频的采集过程主要通过麦克风等设备将环境中的模拟信号采集成PCM或其他编码的原始数据。

1.1 原始视频数据编码

首先了解下描述视频的几个参数:

  • 帧率,指视频每秒钟包括的画面数量(FPS,Frame per second),即帧数。帧率越高,视频就越逼真、越流畅。
  • 分辨率,用于度量图像内数据量多少的一个参数,和视频清晰度息息相关。

    1.1.1 RGB

    RGB图像中,每个像素点都有 红(R)、绿(G)、蓝(B) 三个原色
    RGB
  • RGB24:每像素24位(bits per pixel,bpp)编码的RGB值:使用三个8位无符号整数(0到255)表示红色、绿色和蓝色的强度。一个像素点就是24bit,即3个字节(3B),一张1920 1080的图片就是1920 1080 * 3 / 1024 / 1024 = 2.63MB。
    RGB24
  • RGB32:就是带alpha通道的RGB24,余下的8比特用来表示像素的透明度(Alpha)。

以一个分辨率1920×1280,帧率30的视频为例,以RGB编码,一秒的视频大小是1920×1280x24x30=1769472000bit,约等于211MB,如果是90分钟的视频就是约1112GB。这太大了,因此,我们需要另一种更节省带宽的编码格式。

1.1.2 YUV

YUV颜色编码采用的是 明亮度(Y)色度(UV) 来指定像素的颜色,是利用人眼对亮度敏感而对色度相对不敏感的特点,通过缩减色度采样以减少数据量,并且图像质量不会明显下降的色彩模式。
YUV

  • Y 表示明亮度(Luminance 或 Luma),也就是灰阶值。黑白视频的像素就只有Y。
  • UV 表示的则是色度(Chrominance 或Chroma),作用是描述影像色调和饱和度。UV表示的色域不能代表RGB色域中所有可用的颜色。如下图,里面的正方形是Y=0.5时,UV表示的色域。
    YUV-UV

YUV将亮度(Y)信息和色度(UV)信息分离,并对色度(UV)信息采用更“狠”一点的压缩方案。比起RGB,大多数YUV格式平均使用的每像素位数都少于24位,从而占用更少的带宽。
YUV格式

  • YUV444:完全取样。
  • YUV422:水平2:1取样,垂直完全采样。
  • YUV420:水平2:1取样,垂直2:1采样。是比较常见的格式,比RGB24小了二分之一。

1.1.3 RGB与YUV的相互转换

对于图像显示器来说,它是通过 RGB 模型来显示图像的,而在传输图像数据时又是使用 YUV 模型,这是因为 YUV模型可以节省带宽。因此就需要采集图像时将 RGB 模型转换到 YUV 模型,显示时再将YUV 模型转换为RGB 模型.

  • RGB转YUV
    1
    2
    3
    Y = 0.299 * R + 0.587 * G + 0.114 * B
    U = -0.147 * R - 0.289 * G + 0.436 * B
    V = 0.615 * R - 0.515 * G - 0.100 * B
  • YUV 转RGB
    1
    2
    3
    R = Y + 1.14 * V
    G = Y - 0.39 * U - 0.58 * V
    B = Y + 2.03 * U

1.2 原始音频数据编码

描述PCM数据的几个参数:

  • 采样频率:8kHz(电话)、44.1kHz(CD)、48kHz(DVD)。采样频率越高,数据量就越大,同时音频质量也就越高。
  • 位宽:常用的位宽是 8bit 或者 16bit。位宽表示每一个采样点的大小,位数越多,数据量就越大,同时音频质量也就越高。
  • 声道数:常见的有1(单声道)和2(双声道)。音频的采集和播放是可以叠加的,声道表示声音录制时的音源数量或回放时相应的扬声器数量。
  • 音频帧:一般约定俗成取 2.5ms~60ms 为单位的数据量为一帧音频。这个时间被称之为“采样时间”。

2 处理

2.1 视频处理

视频处理包含美颜、水印、以及各种自定义滤镜等处理。

  • 磨皮的技术术语是“去噪”,也即对图像中的噪点进行去除或者模糊化处理,常见的去噪算法有均值模糊、高斯模糊和中值滤波等。
  • 水印可用于简单是版权保护,或者进行广告设置。
  • 滤镜:把静态图像或者视频的每一帧进行图片处理,通过像素点坐标和RGB颜色值变化实现。

ios可依靠开源库GPUImage实现,android也有对应的android-gpuimage

GPUImage: 基于OpenGL图像和视频处理的跨平台框架。GPUImage提供了各种各样的滤镜,还可以实现磨皮、水印等功能。
OpenGL:OpenGL(Open Graphics Library)是个定义了一个跨编程语言、跨平台的编程接口的规格,它用于三维图象(二维的亦可)。OpenGL是个专业的图形程序接口,是一个功能强大,调用方便的底层图形库。
OpenGL ES: OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL三维图形 API 的子集,针对手机、PDA和游戏主机等嵌入式设备而设计。

2.2 音频处理

音频处理包含混音、降噪和声音特效等处理。

3 编码与封装

即使是YUV420格式的原始视频,数据存储空间还是很大的。这些数据需要经过压缩编码,然后封装成用户可以直接播放的文件,比如mp4、mkv等等。

3.1 编码

  • 视频编码:视频编码是为了将视频像素数据压缩成视频码流,以降低视频的大小,从而方便网络传输和存储。常见的有:H.264、MPEG-4、MPEG-2等。
  • 音频编码:视频编码是为了将音频原始数据转换为音频码流,以便在网络传输。常见的有:AAC、MP3、WMA、AC-3等。

3.1.1 视频编码的原理

为什么巨大的原始视频可以编码成很小的视频呢?这其中的技术是什么呢?核心思想就是去除冗余信息:

  • 空间冗余:图像相邻像素之间有较强的相关性。比如一张纯色图像,所有像素的编码都是一致的。
  • 时间冗余:视频序列的相邻图像之间内容相似。比如一段视频里有十几秒的画面是几乎不动的;或者一段视频里,只有人物(部分像素)在动,背景(其他像素)是几乎不动的。
  • 编码冗余:不同像素值出现的概率不同。
  • 视觉冗余:人的视觉系统对某些细节不敏感。

其中,消除空间冗余、时间冗余和编码冗余并不会导致信息损失,属于无损压缩。而消除视觉冗余是以一定的客观失真换取数据压缩,属于有损压缩。
针对这些不同类型的冗余信息,采用了多种技术来提高视频的压缩比率。其中常见的有预测编码(去除空间和时间冗余)、变换编码(去除空间冗余和视觉冗余)和熵编码(去除编码冗余)。

3.1.2 预测编码

在讲述预测编码前,我们先理解帧的概念。上面有提到,视频的帧率就是每秒的画面数,即帧数。
可以分为3种:

  • I帧 :独立帧,是最完整的画面(占用的空间最大),无需参考其它图像便可独立进行解码。视频序列中的第一个帧,始终都是I帧。
  • P帧 :“帧间预测编码帧”,需要参考前面的I帧或P帧的不同部分,才能进行编码。P帧对前面的P和I参考帧有依赖性,压缩率比较高,占用的空间较小。
    P帧
  • B帧 :“双向预测编码帧”,以前帧后帧作为参考帧。不仅参考前面,还参考后面的帧,所以,它的压缩率最高,可以达到200:1。不过,因为依赖后面的帧,所以不适合实时传输(例如视频会议)。
    B帧

视频处理中的预测编码主要分为两大类:帧内编码帧间编码。通常在视频码流中,I帧全部使用帧内编码,P帧/B帧中的数据可能使用帧内或者帧间编码。

  • 帧内编码:只利用本帧图像内的空间相关性,由当前帧中已编码的部分来推测当前待编码的这一部分数据是什么,预测值与实际值位于同一帧内,去除空间冗余信息。特点是:压缩率相对较低;可以独立解码,不依赖其他帧的数据。
    帧内编码
  • 帧间编码:同时利用空间和时间上的相关性,由这一帧的前(或后)一帧(或几帧)来推测当前待压缩的这一部分数据是什么,利用运动估计(Motion Estimation)和运动补偿(Motion Compensation),去掉时间冗余信息。特点是:压缩率高于帧内预测;不能独立解码,必须在获取参考帧数据之后才能重建当前帧。
    下图是用ffmpeg生成带有移动矢量的视频,然后把每一帧都输出成图片。后图(P 帧)根据与前图(参考帧,I 或 P 帧)参考帧的向量差进行编码。
    帧间编码

3.1.3 变换编码

目前主流的视频编码算法均属于有损编码,通过对视频造成有限而可以容忍的损失,获取相对更高的编码效率。
首先需要将图像信息从空间域通过变换编码 变换 至频域,并计算其变换系数供后续的编码。以离散余弦变换(DCT)为例,首先需要将图像分成互不重叠的图像块。假设一帧图像的大小为1280 x 720,首先将其以网格状的形式分成160 x 90个尺寸为8 x 8的彼此没有重叠的图像块,然后对每个图像块进行DCT变换,从空间域变换为频率域,得出像素的分量。
下图为某个图像经过DCT变换后的系数,数值大的表示高频,数值小的表示低频。数值相差不大的表示像素间的相关性高。人的眼睛对图像的低频特性比如物体的总体亮度之类的信息很敏感,而对图像中的高频细节信息不敏感。
图像经过DCT变换后的系数
然后就进行 量化,通过对低频区的系数进行细量化, 对高频区的系数进行粗量化,去除了人眼不敏感的高频信息,即去除视觉冗余,从而降低信息传送量。下图为量化结果,此时只需将这些非0值进行压缩编码即可。
量化后的DCT系数

3.1.5 熵编码

熵编码具有消除数据之间统计冗余的功能,在编码端作为最后一道工序,将语法元素写入输出码流。
熵编码可分为变长编码和算术编码,其中最常用的是变长编码(最佳编码)。变长编码,就是对出现概率大的符号分配短字长的二进制码,对于出现概率小的符号分配长字长的二进制码,得到符号平均码长最短的码流。即对出现概率大的像素颜色编码分配短编码,从而消除编码冗余。

3.1.1 视频编码的国际标准

编码器经历了数十年的发展,已经从开始的只支持帧内编码演进到现如今的 H.265 和 VP9 为代表的新一代编码器。

  • H.26X:ITU提出了H.261、H.262、H.263、H.264、H.265(最新视频编码系统的标配),这些统称为H.26X系列,主要应用于实时视频通信领域,如会议电视、可视电话等;
  • MPEG:ISO/IEC提出了MPEG1、MPEG2、MPEG4、MPEG7、MPEG21,统称为MPEG系列。
  • VPX:VP8、VP9。最早由 On2 Technologies 开发,随后由 Google 发布。

3.2 封装

封装,就是将已经编码压缩好的视频轨和音频轨,和一些metadata标签信息,一起打包成可供播放的资源文件,比如mp4等。

视频文件格式 视频封装格式
.avi AVI(Audio Video Interleaved)
.wmv, .asf WMV(Windows Media Video)
.mpg, .mpeg, .vob, .dat, .3gp, .mp4 MPEG(Moving Picture Experts Group)
.mkv Matroska
.rm, .rmvb Real Video
.mov QuickTime File Format
.flv Flash Video

可以用使用ffmpeg命令,ffmpeg -i xxx.mp4查看视频的metadata标签信息。
mp4文件信息

参考