从进入公司到现在已经有几年时间了,这段时间里做了不少和音视频相关的工作,包括音频的播放,视频播放还有视频直播。在这个过程中遇到的问题也是各种的,尤其是视频直播,从不断的填坑过程中总结了一些经验,记录下来以备不时之需。
视频的最基本的实现是通过一张张图片不断的变换带来视觉上的动画。一系列的图片不断变换时候,当达到每一秒变换24张的时候我们的人眼就会认为这不是一张张图片变化(幻灯片),而是感觉这是一个视频。
一张张的图片又由非常多的点来组成,这里的不能再分割的点就是像素,他是一个计量单位(用px表示),一张图片的大小我们用横向像素数x竖向像素数表示(例如一张96px96px的图片)。而一个屏幕的大小有物理尺寸,也可以用像素来标定它的尺寸(也就是分辨率),例如我们平时使用的手机的19201080的屏幕。
每个像素点有自己的颜色,通过像素点阵形成彩色图像。每个像素的颜色构成有自己的标准,也就是RGB。
其实他是为了将颜色进行量化的工业界的一种颜色标准,这里分为R:read;G:green;B:blue三个通道,三种颜色经过叠加可以形成各种颜色。各个颜色都由0-255(使用16进制数字表示00-ff)也就是256个级别强度组成,也就是可以组成256256256种颜色(也称为24位色:2的24次方)。同时还可以添加一个透明度通道(Alpha:也分为0-255强度等级),也就形成了ARGB色彩模式(称为32位色:2的32位)。
ARGB_8888:各个通道各占用8个bit的内存;也就是占用8乘4除以8=4byte内存(8bit为1byte)
ARGB_4444:各个通道各占用4个bit的内存;也就是占用4乘4除以8=2byte内存(8bit为1byte)
RGB_888:只有三通道,各个通道各占用8个bit的内存;也就是占用8乘3除以8=3byte内存(8bit为1byte)
RGB_565:只有三通道,R,G,B各占5,6,5个bit的内存;也就是占用5加6加5除以8=2byte内存(8bit为1byte)
这里的Codec指的是一个程序,encode(编码)的本质是压缩而decode(解码)的本质是解压缩。视频文件的本质是图片的“集合”,但是如果这个集合中把每一张图片的详细信息都保存下来传到服务端再传到播放端播放数据量会非常的大。以720p(每一帧图的长为1280px,宽为720p)的视频为例子,每张图片的大小为1280x720x3 bytes,也就是2.7MB,我们可以算一下一个60s的视频要用60242.7也就是3.9G。这么大的数据量是我们不能承受的,无论是存储还是在网络上传输。所以编解码技术肯定势在必行,所以Codec程序就产生了,拍摄端将拍好的源文件经过一定算法编码生成相应的视频文件传输到服务端,播放端从服务端获取视频文件解码成可以播放的文件。说起来简单做起来难,视频编码和解码是一个很复杂的过程,万幸的是目前市面上有很多的规范来指导开发,也有相应的开源框架帮助我们实现。
MPEG:ISO[国际标准组织机构]下的“活动图像专家组”(Moving Picture Experts Group)的缩写,制定“活动图像和音频编码”标准的组织。
做出的贡献:视频编码方面主要是Mpeg1(vcd用的就是它)、Mpeg2(DVD使用)、Mpeg4(的DVDRIP使用的都是它的变种,如:divx,xvid等)、Mpeg4 AVC(正热门);音频编码方面主要是MPEG Audio Layer 1/2、MPEG Audio Layer 3(大名鼎鼎的mp3)、MPEG-2 AAC 、MPEG-4 AAC等等。注意:DVD音频没有采用Mpeg的。
(由ITU[国际电传视讯联盟]主导,侧重网络传输,注意:只是视频编码)
包括H.261、H.262、H.263、H.263+、H.263++、H.264(就是MPEG4 AVC-合作的结晶)、H.265
目前主要使用的是H.264,H.265标准。H.265旨在在有限带宽下传输更高质量的网络视频,仅需原先的一半带宽即可播放相同质量的视频。
我们可以想象一下我们在将一个“图片集”进行压缩的时候,如果我们对每一张图都采用相同的压缩方法,那么在一个长度60s的相对“静止的场景”中是不是就显得特别的“傻”,这时候我们取几个关键的图片出来根据变化的程度保存其他图片变化的数据岂不是很好,这种做法叫做“去冗余”,实际的算法比这个复杂得多。这里我们暂不深入研究。
我们平时所谓的视频文件其实是一种视频容器文件,例如MP4,AVI,FLV等。(百度百科对于视频格式的描述)。说成视频文件其实是不够准确的,因为里面不仅包含了视频数据还包含了音频数据,有的还包含了字幕。它其实是一个结构化的文件,按照一定的规范将视频,音频,字幕等放在指定位置,以方便播放器解码播放。
视频容器文件带.mp4,.flv等后缀的其实是封装格式,不是编码格式,是个扩展名,里面的内容是可变的。例如早前,MP4内部视频是divx和xvid等编码,后来用h.263编码,到现在多是h.264编码,以后应该变成h.265编码了。
例如:当mp4文件里的视频编码格式是h.264的时候,那么,它和内部采用同样编码的MKV、MOV和FLV,是可以无损转换的。可以理解为内部文件一样,就是包装不同。
这里只是介绍一个大概,不具体展开,目的为了帮助理解后面编写具体代码做准备,后面将要涉及使用Android自带Media Api进行视频播放,那里面会涉及视频容器文件大体结构分析,也就是解码过程。
上面提到MP4容器文件是根据上面2.6.1中MPEG系列中的MPEG-4标准来进行封装的。 MP4视频文件封装格式是基于QuickTime容器格式(苹果的)定义的,因此参考QuickTime的格式定义对理解MP4文件格式很有帮助。MP4格式的官方文件后缀名是“.mp4”,还有其他的以mp4为基础进行的扩展或者是阉割版的格式,如:M4V, 3GP, F4V等。
MP4文件中的所有数据都装在box(QuickTime中为atom)中,也就是说MP4文件由若干个box组成,每个box有类型和长度,可以将box理解为一个数据对象块。box中又可能包含子box,层层包裹。下图是使用mp4info(分析mp4文件推荐使用mp4info和QuickTime Atom Viewer工具)打开一个MP4文件:
从图中我们可以看到根目录下有ftyp,mdat,moov三个根box。下面简单介绍一个
:
ftyp(File Type Box):该box有且只有1个,并且只能被包含在文件层,而不能被其他box包含。该box应该被放在文件的最开始,指示该MP4文件应用的相关信息。
mdat(MetaData Box):包含了很多关于视频的原始数据,比如视频的大小,视频的时长,还有一个索引表,这个索引表包含了不同轨道的起始位置(以字节为单位),又因为每个轨道会被分成若干块sample(采样,每一块采样都是可以单独被播放器播放的一段数据,以ms为单位),metadata也会维护一个细粒度更小的索引表,记录了每一块sample的大小,起始位置,对应视频的时间是多少(以字节为单位)等等的信息。
moov(Movie Box):该box包含了文件媒体的metadata信息,“moov”是一个容器类box,具体内容信息由子box诠释。同File Type Box一样,该box有且只有一个,且只被包含在文件层。一般情况下,“moov”会紧随“ftyp”出现。一般情况下,“moov”中会包含1个“mvhd”和若干个“trak”。其中“mvhd”为header box,一般作为“moov”的第一个子box出现(对于其他容器类box来说,头box都应作为首个子box出现)。trak作为包含具体媒体信息载体box,每个track都是独立的,具有自我特征与属性的,因此需要各自描述互不干涉。图中只有两个trak也就是两个轨道box,一个是音频轨道,一个是视频轨道(因为是我自己的程序录制的很清楚)。实际的MP4文件中可能包含多个trak,比如音频轨道可能有中文和英文两个,还有可能要添加辅助的音效轨道。
从图中我们也可以看出这个视频容器文件的很多信息,音频的和视频的。如音频的编码格式mp4a也就是m4a,采样率:44100,两个声道等;视频的avc1(MPEG-4中一种)编码格式,宽高,帧数,刷新率。
看下图是一个大概的流程
例如Android手机直播:从手机摄像头采集视频,经过美颜,滤镜水印等处理和采集的音频封装为相应的容器文件推流到服务端,服务端对视频流进行处理(如分为不同的清晰度等)然后供各个播放端播放。
大概流程和上面的直播相差不大,只是不是实时上传到服务器端并提供播放。而是将录制好的视频文件上传到服务器经过处理提供给播放端播放。