开篇
煊赫一时,望而生畏的音视频开发
时至今日,短视频App可谓是如日中天,一片兴兴向荣。随着短视频的兴起,音视频开发也愈来愈受到重视,可是因为音视频开发涉及知识面比较广,入门门槛相对较高,让许许多多开发者望而生畏。web
为何写这一系列博文
虽然网上有不少的博文总结了音视频打怪升级的路线,可是音视频开发相关的知识都相对独立,有讲“音视频解码相关”的,有讲“OpenGL相关”的,也有讲“FFmpeg相关的”,可是对于新手来讲,把全部的知识衔接串联起来,并很好的理解全部的知识,倒是很是困难的。算法
本人在学习音视频开发的过程当中,深入体会到了因为知识的分散,过渡断层带来的种种困惑和痛苦,所以,但愿经过本身的理解,能够把音视频开发相关的知识总结出来,并造成系列文章,按部就班,剖析各个环节,一则对本身所学作一个总结和巩固,二则但愿能够帮助想入门音视频开发的开发者小伙伴们。api
【声 明】
首先,这一系列文章均基于本身的理解和实践,可能有不对的地方,欢迎你们指正。
其次,这是一个入门系列,涉及的知识也仅限于够用,深刻的知识网上也有许许多多的博文供你们学习了。
最后,写文章过程当中,会借鉴参考其余人分享的文章,会在文章最后列出,感谢这些做者的分享。网络
码字不易,转载请注明出处!数据结构
教程代码:【Github传送门】
目录
1、Android音视频硬解码篇:
1,音视频基础知识
2,音视频硬解码流程
3,音视频播放:音视频同步
4,音视频解封和封装:生成一个MP4
2、使用OpenGL渲染视频画面篇
1,初步了解OpenGL ES
2,使用OpenGL渲染视频画面
3,OpenGL渲染多视屏,实现画中画
4,深刻了解OpenGL之EGL
5,OpenGL FBO数据缓冲区
6,Android音视频硬编码:生成一个MP4
3、Android FFmpeg音视频解码篇
1,FFmpeg so库编译
2,Android 引入FFmpeg
3,Android FFmpeg视频解码播放
4,Android FFmpeg+OpenSL ES音频解码播放
5,Android FFmpeg+OpenGL ES播放视频
6,Android FFmpeg简单合成MP4:视屏解封与从新封装
7,Android FFmpeg视频编码
本文你能够了解到
做为开篇的文章,咱们先来看看音视频由什么构成的,以及一些常见的术语和概念。框架
1、视频是什么?
动画书
不知道你们小时候是否玩过一种动画小人书,连续翻动的时候,小人书的画面就会变成一个动画,相似如今的gif格式图片。ide
动画书:来源网络学习
原本是一本静态的小人书,经过翻动之后,就会变成一个有趣的小动画,若是画面够多,翻动速度够快的话,这其实就是一个小视频。动画
而视频的原理正是如此,因为人类眼睛的特殊结构,画面快速切换时,画面会有残留,感受起来就是连贯的动做。因此,视频就是由一系列图片构成的。编码
视频帧
帧,是视频的一个基本概念,表示一张画面,如上面的翻页动画书中的一页,就是一帧。一个视频就是由许许多多帧组成的。
帧率
帧率,即单位时间内帧的数量,单位为:帧/秒 或fps(frames per second)。如动画书中,一秒内包含多少张图片,图片越多,画面越顺滑,过渡越天然。
帧率的通常如下几个典型值:
24/25 fps:1秒 24/25 帧,通常的电影帧率。
30/60 fps:1秒 30/60 帧,游戏的帧率,30帧能够接受,60帧会感受更加流畅逼真。
85 fps以上人眼基本没法察觉出来了,因此更高的帧率在视频里没有太大意义。
色彩空间
这里咱们只讲经常使用到的两种色彩空间。
RGB
RGB的颜色模式应该是咱们最熟悉的一种,在如今的电子设备中应用普遍。经过R G B三种基础色,能够混合出全部的颜色。
YUV
这里着重讲一下YUV,这种色彩空间并非咱们熟悉的。这是一种亮度与色度分离的色彩格式。
早期的电视都是黑白的,即只有亮度值,即Y。有了彩色电视之后,加入了UV两种色度,造成如今的YUV,也叫YCbCr。
Y:亮度,就是灰度值。除了表示亮度信号外,还含有较多的绿色通道量。
U:蓝色通道与亮度的差值。
V:红色通道与亮度的差值。
采用YUV有什么优点呢?
人眼对亮度敏感,对色度不敏感,所以减小部分UV的数据量,人眼却没法感知出来,这样能够经过压缩UV的分辨率,在不影响观感的前提下,减少视频的体积。
RGB和YUV的换算
Y = 0.299R + 0.587G + 0.114B
U = -0.147R - 0.289G + 0.436B
V = 0.615R - 0.515G - 0.100B
——————————————————
R = Y + 1.14V
G = Y - 0.39U - 0.58V
B = Y + 2.03U
1
2
3
4
5
6
7
2、音频是什么?
音频数据的承载方式最经常使用的是脉冲编码调制,即PCM。
在天然界中,声音是接二连三的,是一种模拟信号,那怎样才能把声音保存下来呢?那就是把声音数字化,即转换为数字信号。
咱们知道声音是一种波,有本身的振幅和频率,那么要保存声音,就要保存声音在各个时间点上的振幅。
而数字信号并不能连续保存全部时间点的振幅,事实上,并不须要保存连续的信号,就能够还原到人耳可接受的声音。
根据奈奎斯特采样定理:为了避免失真地恢复模拟信号,采样频率应该不小于模拟信号频谱中最高频率的2倍。
根据以上分析,PCM的采集步骤分为如下步骤:
模拟信号->采样->量化->编码->数字信号
音频采样
采样率和采样位数
采样率,即采样的频率。
上面提到,采样率要大于原声波频率的2倍,人耳能听到的最高频率为20kHz,因此为了知足人耳的听觉要求,采样率至少为40kHz,一般为44.1kHz,更高的一般为48kHz。
采样位数,涉及到上面提到的振幅量化。波形振幅在模拟信号上也是连续的样本值,而在数字信号中,信号通常是不连续的,因此模拟信号量化之后,只能取一个近似的整数值,为了记录这些振幅值,采样器会采用一个固定的位数来记录这些振幅值,一般有8位、16位、32位。
位数 最小值 最大值
8 0 255
16 -32768 32767
32 -2147483648 2147483647
位数越多,记录的值越准确,还原度越高。
最后就是编码了。因为数字信号是由0,1组成的,所以,须要将幅度值转换为一系列0和1进行存储,也就是编码,最后获得的数据就是数字信号:一串0和1组成的数据。
整个过程以下:
[图片上传失败…(image-8c5d9f-1568988187211)]
声道数
声道数,是指支持能不一样发声(注意是不一样声音)的音响的个数。
单声道:1个声道
双声道:2个声道
立体声道:默认为2个声道
立体声道(4声道):4个声道
码率
码率,是指一个数据流中每秒钟能经过的信息量,单位bps(bit per second)
码率 = 采样率 采样位数 声道数
3、为何要编码
这里的编码和上面音频中提到的编码不是同个概念,而是指压缩编码。
咱们知道,在计算机的世界中,一切都是0和1组成的,音频和视频数据也不例外。因为音视频的数据量庞大,若是按照裸流数据存储的话,那将须要耗费很是大的存储空间,也不利于传送。而音视频中,其实包含了大量0和1的重复数据,所以能够经过必定的算法来压缩这些0和1的数据。
特别在视频中,因为画面是逐渐过渡的,所以整个视频中,包含了大量画面/像素的重复,这正好提供了很是大的压缩空间。
所以,编码能够大大减少音视频数据的大小,让音视频更容易存储和传送。
4、视频编码
视频编码格式
视频编码格式有不少,好比H26x系列和MPEG系列的编码,这些编码格式都是为了适应时代发展而出现的。
其中,H26x(1/2/3/4/5)系列由ITU(International Telecommunication Union)国际电传视讯联盟主导
MPEG(1/2/3/4)系列由MPEG(Moving Picture Experts Group, ISO旗下的组织)主导。
固然,他们也有联合制定的编码标准,那就是如今主流的编码格式H264,固然还有下一代更先进的压缩编码标准H265。
H264编码简介
H264是目前最主流的视频编码标准,因此咱们后续的文章中主要以该编码格式为基准。
H264由ITU和MPEG共同定制,属于MPEG-4第十部份内容。
因为H264编码算法十分复杂,不是一时半刻可以讲清楚的,也不在本人目前的能力范围内,因此这里只简单介绍在平常开发中须要了解到的概念。实际上,视频的编码和解码部分一般由框架(如Android硬解/FFmpeg)完成,通常的开发者并不会接触到。
视频帧
咱们已经知道,视频是由一帧一帧画面构成的,可是在视频的数据中,并非真正按照一帧一帧原始数据保存下来的(若是这样,压缩编码就没有意义了)。
H264会根据一段时间内,画面的变化状况,选取一帧画面做为完整编码,下一帧只记录与上一帧完整数据的差异,是一个动态压缩的过程。
在H264中,三种类型的帧数据分别为
I帧:帧内编码帧。就是一个完整帧。
P帧:前向预测编码帧。是一个非完整帧,经过参考前面的I帧或P帧生成。
B帧:双向预测内插编码帧。参考先后图像帧编码生成。B帧依赖其前最近的一个I帧或P帧及其后最近的一个P帧。
图像组:GOP和关键帧:IDR
全称:Group of picture。指一组变化不大的视频帧。
GOP的第一帧成为关键帧:IDR
IDR都是I帧,能够防止一帧解码出错,致使后面全部帧解码出错的问题。当解码器在解码到IDR的时候,会将以前的参考帧清空,从新开始一个新的序列,这样,即使前面一帧解码出现重大错误,也不会蔓延到后面的数据中。
注:关键帧都是I帧,可是I帧不必定是关键帧
DTS与PTS
DTS全称:Decoding Time Stamp。标示读入内存中数据流在何时开始送入解码器中进行解码。也就是解码顺序的时间戳。
PTS全称:Presentation Time Stamp。用于标示解码后的视频帧何时被显示出来。
在没有B帧的状况下,DTS和PTS的输出顺序是同样的,一旦存在B帧,PTS和DTS则会不一样。
帧的色彩空间
前面咱们介绍了RGB和YUV两种图像色彩空间。H264采用的是YUV。
YUV存储方式分为两大类:planar 和 packed。
planar:先存储全部Y,紧接着存储全部U,最后是V;
packed:每一个像素点的 Y、U、V 连续交叉存储。
planar以下:
YUV Planar
packed以下:
YUV Packed
不过pakced存储方式已经很是少用,大部分视频都是采用planar存储方式。
上面说过,因为人眼对色度敏感度低,因此能够经过省略一些色度信息,即亮度共用一些色度信息,进而节省存储空间。所以,planar又区分了如下几种格式: YUV44四、 YUV42二、YUV420。
YUV 4:4:4采样,每个Y对应一组UV份量。
YUV 4:2:2采样,每两个Y共用一组UV份量。
YUV 4:2:0采样,每四个Y共用一组UV份量。
其中,最经常使用的就是YUV420。
YUV420格式存储方式
YUV420属于planar存储方式,可是又分两种类型:
YUV420P:三平面存储。数据组成为YYYYYYYYUUVV(如I420)或YYYYYYYYVVUU(如YV12)。
YUV420SP:两平面存储。分为两种类型YYYYYYYYUVUV(如NV12)或YYYYYYYYVUVU(如NV21)
关于H264的编码算法和数据结构,涉及的知识和篇幅不少(如网络抽象层NAL、SPS、PPS),本文再也不深刻细说,网上也有比较多的教程讲解,有兴趣能够自行深刻学习。
入门理解H264编码
5、音频编码
音频编码格式
原始的PCM音频数据也是很是大的数据量,所以也须要对其进行压缩编码。
和视频编码同样,音频也有许多的编码格式,如:WAV、MP三、WMA、APE、FLAC等等,音乐发烧友应该对这些格式很是熟悉,特别是后两种无损压缩格式。
可是,咱们今天的主角不是他们,而是另一个叫AAC的压缩格式。
AAC是新一代的音频有损压缩技术,一种高压缩比的音频压缩算法。在MP4视频中的音频数据,大多数时候都是采用AAC压缩格式。
AAC编码简介
AAC格式主要分为两种:ADIF、ADTS。
ADIF:Audio Data Interchange Format。 音频数据交换格式。这种格式的特征是能够肯定的找到这个音频数据的开始,不需进行在音频数据流中间开始的解码,即它的解码必须在明肯定义的开始处进行。这种格式经常使用在磁盘文件中。
ADTS:Audio Data Transport Stream。 音频数据传输流。这种格式的特征是它是一个有同步字的比特流,解码能够在这个流中任何位置开始。它的特征相似于mp3数据流格式。
ADTS能够在任意帧解码,它每一帧都有头信息。ADIF只有一个统一的头,因此必须获得全部的数据后解码。且这两种的header的格式也是不一样的,目前通常编码后的都是ADTS格式的音频流。
ADIF数据格式:
header raw_data
ADTS 一帧 数据格式(中间部分,左右省略号为先后数据帧):
ADTS
AAC内部结构也再也不赘述,能够参考AAC 文件解析及解码流程
6、音视频容器
细心的读者可能已经发现,前面咱们介绍的各类音视频的编码格式,没有一种是咱们平时使用到的视频格式,好比:mp四、rmvb、avi、mkv、mov…
没错,这些咱们熟悉的视频格式,实际上是包裹了音视频编码数据的容器,用来把以特定编码标准编码的视频流和音频流混在一块儿,成为一个文件。
例如:mp4支持H26四、H265等视频编码和AAC、MP3等音频编码。
mp4是目前最流行的视频格式,在移动端,通常将视频封装为mp4格式。
7、硬解码和软解码
硬解和软解的区别
咱们在一些播放器中会看到,有硬解码和软解码两种播放形式给咱们选择,可是咱们大部分时候并不能感受出他们的区别,对于普通用户来讲,只要能播放就好了。
那么他们内部究竟有什么区别呢?
在手机或者PC上,都会有CPU、GPU或者解码器等硬件。一般,咱们的计算都是在CPU上进行的,也就是咱们软件的执行芯片,而GPU主要负责画面的显示(是一种硬件加速)。
所谓软解码,就是指利用CPU的计算能力来解码,一般若是CPU的能力不是很强的时候,一则解码速度会比较慢,二则手机可能出现发热现象。可是,因为使用统一的算法,兼容性会很好。
硬解码,指的是利用手机上专门的解码芯片来加速解码。一般硬解码的解码速度会快不少,可是因为硬解码由各个厂家实现,质量良莠不齐,很是容易出现兼容性问题。
Android平台的硬解码
终于来到有关Android的部分了,做为本文的结尾,也算是为下一篇文章开一个头。
MediaCodec 是Android 4.1(api 16)版本引入的编解码接口,是全部想在Android上开发音视频的开发人员绕不开的坑。
因为Android碎片化严重,虽然通过多年的发展,Android硬解已经有了很大改观,但实际上各个厂家实现不一样, 仍是会有一些意想不到的坑。
相对于FFmpeg,Android原生硬解码仍是相对容易入门一些,因此接下来,我将会从MediaCodec入手,讲解如何实现视频的编解码,以及引入OpenGL实现对视频的编辑,最后才引入FFmpeg来实现软解,算是一个比较常规的音视频开发入门流程吧。