0%

音视频基本概念

视频封装格式

将已编码压缩好的视频轨道、音频轨道和元数据(视频基本信息如标题、字幕等)按照一定的格式规范,打包放到一个文件中,形成特定文件格式的视频文件。

封装格式主要分为两大类:面向存储的和面向流媒体的。

  • 面向存储的,常见的有 AVI、ASF(WMA/WMV)、MP4、MKV、RMVB(RM/RA)等;
  • 面向流媒体的,常见的有 FLV、TS(需要配合流媒体网络传输协议,如 HLS、RTMP 等),MP4 也支持流媒体方式(配合 HTTP 等)。

流媒体协议及其封装格式

  • DASH + fMP4 + MPD(Dynamic Adaptive Streaming over HTTP):使用 fragmented MP4(fMP4)格式,将 MP4 视频分割为多个分片,每个分片可以存在不同的编码形式(如分辨率、码率等);播放器端可自由选择需要播放的视频分片,实现自适应多码率、不同画质内容的无缝切换,提供更好的播放体验。其中 MPD 文件类似 HLS 的 m3u8 文件,国外视频网站如 YouTube、Netflix 等较多使用 DASH。
  • HLS + TS + M3U8(HTTP Live Streaming):苹果公司推出的基于 HTTP 的流媒体网络传输协议,视频的默认封装格式是 TS,除了多个 TS 分片文件,还定义了用来控制播放的 m3u8 索引文件(文本文件),可以规避普通 MP4 长时间缓冲头部数据的问题,比较适合点播场景。
  • HLS + fMP4(HTTP Live Streaming with fragmented MP4):此处单列,但本质上还是 HLS 协议。苹果公司于 WWDC 2016 宣布新的 HLS 标准支持文件封装格式为 fragmented MP4,使用方法与 TS 分片类似,意味着一次转码可同时打包成 DASH 和 HLS。
  • MP4:经典的视频封装格式,移动端(iOS、Android)、PC Web 多终端都能良好支持。但 MP4 的视频文件头太大,结构复杂;如果视频较长(如数小时),则其文件头会过大,影响视频加载速度,故更适合短视频场景。
    MP4 由一个个的 box(以前叫 atom)组成,所有的 Metadata(媒体描述元数据),包括定义媒体的排列和时间信息的数据都包含在这样的一些结构 box 中。Metadata 对媒体数据(比如视频帧)引用说明,而媒体数据在这些引用文件中的排列关系全部在第一个主文件中的 metadata 描述,这样就会导致视频时长越大文件头就会越大、加载越慢。
  • FLV:Adobe 公司推出的标准。

HLS(包括 HLS+fMP4)和 DASH 是最常用的自适应流媒体传输技术(Adaptive Video Streaming),推荐使用。

码率

定义:视频文件在单位时间内使用的数据流量

单位:bps,Kbps,Mbps

计算公式:文件体积 = 时间 × 码率 / 8 (网络上常见的一部60分钟的码率为1Mbps的720P的视频文件,其体积就大概为3600秒×1Mb/8=450MB)

等响曲线

等响曲线的横轴是频率,纵轴是声压级,每条曲线对人来说响度是一样的,可以看出人耳对3~4kHz频率范围内的声音比较敏感,同样的响度需要达到的声压级最低。

声音模拟信号数字化过程

采样、量化和编码。

采样:在时间轴上对信号进行数字化。

根据奈奎斯特定理(也称为采样定理),按比声音最高频率高2倍以上的频率对声音进行采样(也称为AD转换)。对于高质量的音频信号,其频率范围(人耳能够听到的频率范围)是20Hz~20kHz,所以采样频率一般为44.1kHz,这样就可以保证采样声音达到20kHz也能被数字化。

量化:在幅度轴上对信号进行数字化。

比如用16比特的二进制信号来表示声音的一个采样,而16比特(一个short)所表示的范围是[-32768,32767],共有65536个可能取值,因此最终模拟的音频信号在幅度上也分为了65536层。

编码:按照一定的格式记录采样和量化后的数字数据。

音频的裸数据格式:脉冲编码调制(Pulse Code Modulation,PCM)数据。

描述PCM数据:量化格式(sampleFormat)、采样率(sampleRate)、声道数(channel)。(以CD的音质为例:量化格式(有的地方描述为位深度)为16比特(2字节),采样率为44100,声道数为2,这些信息就描述了CD的音质。)

数据比特率:描述声音格式的大小,即1秒时间内的比特数目,它用于衡量音频数据单位时间内的容量大小。

CD 音质的数据的比特率:44100 * 16 * 2 = 1378.125kbps

1分钟 CD 音质的数据占用存储空间:1378.125 * 60 / 8 / 1024 = 10.09MB

分贝:两个相同的物理量(例如,A1和A0)之比取以10为底的对数并乘以10(或20),即:N= 10 * lg(A1 / A0)分贝符号为“dB”,它是无量纲的。式中A0是基准量(或参考量), A1是被量度量。

音频编码

压缩算法包括有损压缩和无损压缩。

压缩编码算法:PCM、WAV、AAC、MP3、Ogg。

WAV编码

PCM(脉冲编码调制)是Pulse Code Modulation的缩写。前面已经介绍过PCM大致的工作流程,而WAV编码的一种实现(有多种实现方式,但是都不会进行压缩操作)就是在PCM数据格式的前面加上44字节,分别用来描述PCM的采样率、声道数、数据格式等信息。

特点:音质非常好,大量软件都支持。

适用场合:多媒体开发的中间文件、保存音乐和音效素材。

MP3编码

MP3具有不错的压缩比,使用LAME编码(MP3编码格式的一种实现)的中高码率的MP3文件,听感上非常接近源WAV文件,当然在不同的应用场景下,应该调整合适的参数以达到最好的效果。

特点:音质在128Kbit/s以上表现还不错,压缩比比较高,大量软件和硬件都支持,兼容性好。

适用场合:高比特率下对兼容性有要求的音乐欣赏。

AAC编码

AAC是新一代的音频有损压缩技术,它通过一些附加的编码技术(比如PS、SBR等),衍生出了LC-AAC、HE-AAC、HE-AAC v2三种主要的编码格式。LC-AAC是比较传统的AAC,相对而言,其主要应用于中高码率场景的编码(≥80Kbit/s); HE-AAC(相当于AAC+SBR)主要应用于中低码率场景的编码(≤80Kbit/s);而新近推出的HE-AAC v2(相当于AAC+SBR+PS)主要应用于低码率场景的编码(≤48Kbit/s)。事实上大部分编码器都设置为≤48Kbit/s自动启用PS技术,而>48Kbit/s则不加PS,相当于普通的HE-AAC。

特点:在小于128Kbit/s的码率下表现优异,并且多用于视频中的音频编码。

适用场合:128Kbit/s以下的音频编码,多用于视频中音频轨的编码。

Ogg编码

Ogg是一种非常有潜力的编码,在各种码率下都有比较优秀的表现,尤其是在中低码率场景下。Ogg除了音质好之外,还是完全免费的,这为Ogg获得更多的支持打好了基础。Ogg有着非常出色的算法,可以用更小的码率达到更好的音质,128Kbit/s的Ogg比192Kbit/s甚至更高码率的MP3还要出色。但目前因为还没有媒体服务软件的支持,因此基于Ogg的数字广播还无法实现。Ogg目前受支持的情况还不够好,无论是软件上的还是硬件上的支持,都无法和MP3相提并论。

特点:可以用比MP3更小的码率实现比MP3更好的音质,高中低码率下均有良好的表现,兼容性不够好,流媒体特性不支持。

适用场合:语音聊天的音频消息场景。

三原色

红绿蓝三种色光无法被分解,故称为三原色光,等量的三原色光相加会变为白光,即白光中含有等量的红光(R)、绿光(G)、蓝光(B)。

分辨率

假设一部手机屏幕的分辨率是1280×720,说明水平方向有720个像素点,垂直方向有1280个像素点,所以整个手机屏幕就有1280×720个像素点(这也是分辨率的含义)。每个像素点都由三个子像素点组成,这些密密麻麻的子像素点在显微镜下可以看得一清二楚。当要显示某篇文字或者某幅图像时,就会把这幅图像的每一个像素点的RGB通道分别对应的屏幕位置上的子像素点绘制到屏幕上,从而显示整个图像。

像素里面的子像素

浮点表示

取值范围为0.0~1.0,比如,在OpenGL ES中对每一个子像素点的表示使用的就是这种表达方式。

整数表示

取值范围为0~255或者00~FF,8个比特表示一个子像素,32个比特表示一个像素,这就是类似于某些平台上表示图像格式的RGBA_8888数据格式。比如,Android平台上RGB_565的表示方法为16比特模式表示一个像素,R用5个比特来表示,G用6个比特来表示,B用5个比特来表示。

计算

对于一幅图像,一般使用整数表示方法来进行描述,比如计算一张1280×720的RGBA_8888图像的大小,可采用如下方式:1280 * 720 * 4 = 3.516MB

图像的压缩格式

JPEG压缩:JPEG是静态图像压缩标准,由ISO制定。JPEG图像压缩算法在提供良好的压缩性能的同时,具有较好的重建质量。这种算法被广泛应用于图像处理领域,当然其也是一种有损压缩。在很多网站如淘宝上使用的都是这种压缩之后的图片,但是,这种压缩不能直接应用于视频压缩,因为对于视频来讲,还有一个时域上的因素需要考虑,也就是说,不仅仅要考虑帧内编码,还要考虑帧间编码。

YUV表示方式

视频帧的裸数据表示:YUV主要应用于优化彩色视频信号的传输,使其向后兼容老式黑白电视。与RGB视频信号传输相比,它最大的优点在于只需要占用极少的频宽(RGB要求三个独立的视频信号同时传输)。

其中“Y”表示明亮度(Luminance或Luma),也称灰阶值;而“U”和“V”表示的则是色度(Chrominance或Chroma),它们的作用是描述影像的色彩及饱和度,用于指定像素的颜色。

“亮度”是透过RGB输入信号来建立的,方法是将RGB信号的特定部分叠加到一起。“色度”则定义了颜色的两个方面——色调与饱和度,分别用Cr和Cb来表示。其中,Cr反映了RGB输入信号红色部分与RGB信号亮度值之间的差异,而Cb反映的则是RGB输入信号蓝色部分与RGB信号亮度值之间的差异。

之所以采用YUV色彩空间,是因为它的亮度信号Y和色度信号U、V是分离的。如果只有Y信号分量而没有U、V分量,那么这样表示的图像就是黑白灰度图像。

彩色电视采用YUV空间正是为了用亮度信号Y解决彩色电视机与黑白电视机的兼容问题,使黑白电视机也能接收彩色电视信号,最常用的表示形式是Y、U、V都使用8个字节来表示,所以取值范围就是0~255。

YUV最常用的采样格式是4:2:0,4:2:0并不意味着只有Y、Cb而没有Cr分量。它指的是对每行扫描线来说,只有一种色度分量是以2:1的抽样率来存储的。相邻的扫描行存储着不同的色度分量,也就是说,如果某一行是4:2:0,那么其下一行就是4:0:2,再下一行是4:2:0,以此类推。对于每个色度分量来说,水平方向和竖直方向的抽样率都是2:1,所以可以说色度的抽样率是4:1。

相较于RGB,我们可以计算一帧为1280×720的视频帧,用YUV420P的格式来表示,其数据量的大小如下:

1280 * 720 * 1 + 1280 * 720 * 0.5 = 1.318MB

如果fps(1秒的视频帧数目)是24,按照一般电影的长度90分钟来计算,那么这部电影用YUV420P的数据格式来表示的话,其数据量的大小就是:

1.318MB * 24fps * 90min * 60s = 166.8GB

YUV和RGB的转化

凡是渲染到屏幕上的东西(文字、图片或者其他),都要转换为RGB的表示形式。

iOS:中使用摄像头采集出YUV数据之后,上传显卡成为一个纹理ID,这个时候就需要做YUV到RGB的转换(具体的细节会在后面的章节中详细讲解)。在iOS的摄像头采集出一帧数据之后(CMSampleBufferRef),我们可以在其中调用CVBufferGetAttachment来获取YCbCrMatrix,用于决定使用哪一个矩阵进行转换。

Android:由于其是直接纹理ID的回调,所以不涉及这个问题。其他场景下需要大家自行寻找对应的文档,以找出适合的转换矩阵进行转换。

视频编码

视频压缩也是通过去除冗余信息来进行压缩的。相较于音频数据,视频数据有极强的相关性,也就是说有大量的冗余信息,包括空间上的冗余信息和时间上的冗余信息。

使用帧间编码技术可以去除时间上的冗余信息:运动补偿,运动表示,运动估计。使用帧内编码技术可以去除空间上的冗余信息。

ISO制定的MPEG(Motion JPEG):MPEG算法是适用于动态视频的压缩算法,它除了对单幅图像进行编码外,还利用图像序列中的相关原则去除冗余,这样可以大大提高视频的压缩比。主要包括这样几个版本:Mpeg1(用于VCD)、Mpeg2(用于DVD)、Mpeg4 AVC(现在流媒体使用最多的就是它了)。

ITU-T制定的H.261、H.262、H.263、H.264一系列视频编码标准是一套单独的体系。现在使用最多的就是H.264标准,H.264创造了多参考帧、多块类型、整数变换、帧内预测等新的压缩技术,使用了更精细的分像素运动矢量(1/4、1/8)和新一代的环路滤波器,这使得压缩性能得到大大提高,系统也变得更加完善。

IPB帧

视频压缩中,每帧都代表着一幅静止的图像。

I帧:帧内编码帧(intra picture), I帧通常是每个GOP(MPEG所使用的一种视频压缩技术)的第一个帧,经过适度地压缩,作为随机访问的参考点,可以当成静态图像。I帧可以看作一个图像经过压缩后的产物,I帧压缩可以得到6:1的压缩比而不会产生任何可觉察的模糊现象。I帧压缩可去掉视频的空间冗余信息,下面即将介绍的P帧和B帧是为了去掉时间冗余信息。

P帧:前向预测编码帧(predictive-frame),通过将图像序列中前面已编码帧的时间冗余信息充分去除来压缩传输数据量的编码图像,也称为预测帧。

B帧:双向预测内插编码帧(bi-directional interpolated prediction frame),既考虑源图像序列前面的已编码帧,又顾及源图像序列后面的已编码帧之间的时间冗余信息,来压缩传输数据量的编码图像,也称为双向预测帧。

从解码的角度来理解IPB帧:

I帧自身可以通过视频解压算法解压成一张单独的完整视频画面,所以I帧去掉的是视频帧在空间维度上的冗余信息。

P帧需要参考其前面的一个I帧或者P帧来解码成一张完整的视频画面。

B帧则需要参考其前一个I帧或者P帧及其后面的一个P帧来生成一张完整的视频画面,所以P帧与B帧去掉的是视频帧在时间维度上的冗余信息。

IDR帧

在H264的概念中有一个帧称为IDR帧,那么IDR帧与I帧的区别是什么呢?首先来看一下IDR的英文全称instantaneous decoding refresh picture,因为H264采用了多帧预测,所以I帧之后的P帧有可能会参考I帧之前的帧,这就使得在随机访问的时候不能以找到I帧作为参考条件,因为即使找到I帧,I帧之后的帧还是有可能解析不出来,而IDR帧就是一种特殊的I帧,即这一帧之后的所有参考帧只会参考到这个IDR帧,而不会再参考前面的帧。在解码器中,一旦收到一个IDR帧,就会立即清理参考帧缓冲区,并将IDR帧作为被参考的帧。

PTS与DTS

DTS主要用于视频的解码,英文全称是Decoding Time Stamp, PTS主要用于在解码阶段进行视频的同步和输出,全称是Presentation Time Stamp。在没有B帧的情况下,DTS和PTS的输出顺序是一样的。因为B帧打乱了解码和显示的顺序,所以一旦存在B帧,PTS与DTS势必就会不同。

FFmpeg中使用的PTS和DTS的概念:FFmpeg中使用AVPacket结构体来描述解码前或编码后的压缩数据,用AVFrame结构体来描述解码后或编码前的原始数据。对于视频来说,AVFrame就是视频的一帧图像,这帧图像什么时候显示给用户,取决于它的PTS。DTS是AVPacket里的一个成员,表示该压缩包应该在什么时候被解码,如果视频里各帧的编码是按输入顺序(显示顺序)依次进行的,那么解码和显示时间应该是一致的,但是事实上,在大多数编解码标准(如H.264或HEVC)中,编码顺序和输入顺序并不一致,于是才会需要PTS和DTS这两种不同的时间戳。

GOP

两个I帧之间形成的一组图片,就是GOP(Group Of Picture)的概念。

通常在为编码器设置参数的时候,必须要设置gop_size的值,其代表的是两个I帧之间的帧数目。前面已经讲解过,一个GOP中容量最大的帧就是I帧,所以相对来讲,gop_size设置得越大,整个画面的质量就会越好,但是在解码端必须从接收到的第一个I帧开始才可以正确解码出原始图像,否则会无法正确解码(这也是前面提到的I帧可以作为随机访问的帧)。在提高视频质量的技巧中,还有个技巧是多使用B帧,一般来说,I的压缩率是7(与JPG差不多), P是20, B可以达到50,可见使用B帧能节省大量空间,节省出来的空间可以用来更多地保存I帧,这样就能在相同的码率下提供更好的画质。所以我们要根据不同的业务场景,适当地设置gop_size的大小,以得到更高质量的视频。

参考

音视频技术原理及应用

音视频基本概念

自己动手写编解码器

开源解码器 x264

开源解码器 x265