前沿
随着移动技术的成熟和即将到来的5G时代 ,越来越多的公司开发移动视频软件来占领市场,随着抖音的登场 视频APP现已是火海一片,BAT纷纷入场。
为了能在红海中分一杯羹 我司决定开发一款赛马的视频观看项目,在项目的开发中 对苹果的AVFoundation框架进行了了解和学习 在学习过程中越来越佩服AVFoundation
框架的厉害之处。我会分几篇文章来分析AVFoundation
中常用的API和类
AVFoundation入门
在学习AVFoundation
之初,最大的挑战就是理解该框架所提供的大量类及其功能。该框架包含的类超过100个、大量协议的集合及许多不同的功能和常量。在第一次遇到这些问题时看似掌握这个框架有一定的难度, 但是如果你将这个框架仔细地按功能单元进行分解,就会变得比较容易理解。下面就看一下 AVFoundation所提供的一些核心功能。
-
音频播放和记录
AVAudioPlayer
和AVAudioRecorder
可以在应用程序中提供一种更简单的整合音频播放和记录的功能。这些方法并不是AVFoundation
用于播放和记录音频的唯一方式,却是学习起来最简单并且功能最强大的方法
-
媒体文件检查
AVFoundation
提供检查正在使用的媒体文件的功能。可以查看这些媒体资源来确定是否适合一些特定的任务,比如是否可以用于回放或其是否可以被编辑和导出。还可以获取该媒体资源相关的技术参数,比如内容持续时间 创建日期或首选播放音量等。此外,该框架还基于AVMetadataItem
类提供功能强大的元数据支持。这就允许开发者读写关于媒体资源的描述信息。
-
视频播放
AVFoundation
框架可以让你播放从本地文件或远程流中获取的视频资源,并对视频播放和内容的展示进行控制。这一部分的核心类是AVPlayer
和AVPlayerItem
,正是这两个类让你能够对资源的播放进行控制,此外它还可以整合其他更高级的功能,如控制子标题和章节信息等。或者让你链接访问音频和视频这两个不同的资源。
-
媒体捕捉
AVFoundation
提供了一个丰富的API集来让你可以对这些设备进行精密控制。摄像头捕捉的核心类是AVCaptureSession
,其作为所有活动的汇集点来接收摄像头设备由各路流发过来的电影和图片。这也是AVFoundation
框架的一个可靠功能。
-
媒体编辑
AVFoundation
框架语允许创建可以将多个音频和视频资源进行组合的应用程序,允许修改和编辑独立的媒体片段,随时修改音频文件的参数以及添加动画标题和场景切换效果。
AVFoundation
有关资源组合的功能源于AVAsset
的子类AVComposition
。AVComposition
中的轨道都是AVAssetTrack
的子类AVCompositionTrack
。一个组合轨迹本身由一个或多个媒体片断组成,由AVCompositionTrackSegment
类定义,代表这个组合中的实际媒体区域,描述如下图所示:
AVComposition
和AVCompositionTrack
都是不可变对象,提供对资源的只读操作。这些对象提供了一个合适的接口让应用程序的一部分可以进行播放或处理。但当需要创建自己的组合时,就需要使用AVMutableComposition
和AVMutableCompositionTrack
所提供的可变子类。要创建自定义组合,需指定在将要添加到组合的源媒体的时间范围,还要指定要添加片段的每个轨道的位置。
-
媒体处理
虽然通过AVFoundation
框架可以在不通过对媒体资源字节一级进行操作的前提下实现大量功能,但有时你可能还是需要访问更低层的数据并对其进行操作。幸运的是,当需要执行更高级的媒体处理任务时,可以使用AVAssetReader
和AVAssetWriter
类来实现这些功能。这些类提供直接访问视频帧和音频样本的功能,所以可以对媒体资源进行任何更高级的处理。
视频的基本知识点
- 流媒体开发:
- 网络层(socket或st)负责传输
- 协议层(rtmp或hls)负责网络打包
- 封装层(flv、ts)负责编解码数据的封装
- 编码层(h.264和aac)负责图像,音频压缩
不经过压缩编码的视频,根本没办法保存,更何况网络中的传输,视频录制完成后,要先编码,再传输,在解码,再播放(重现)
帧:每帧代表一幅静止的图像
-
序列GOP: (
Group of Pictures
)画面组,一个GOP就是一组连续的画面,每个画面都是一帧,一个GOP就是很多帧的集合. (直播的数据,其实是一组图片,包括I帧、P帧、B帧,当用户第一次观看的时候,会寻找I帧,而播放器会到服务器寻找到最近的I帧反馈给用户。因此,GOP Cache增加了端到端延迟,因为它必须要拿到最近的I帧). GOP Cache的长度越长,画面质量越好- 在H264中图像以序列为单位进行组织,一个序列是一段图像编码后的数据流。
- 一个序列的第一个图像叫做 IDR 图像(立即刷新图像),IDR 图像都是 I 帧图像。
- H.264 引入 IDR 图像是为了解码的重同步,当解码器解码到 IDR 图像时,立即将参考帧队列清空,将已解码的数据全部输出或抛弃,重新查找参数集,开始一个新的序列。
- 这样,如果前一个序列出现重大错误,在这里可以获得重新同步的机会。
- IDR图像之后的图像永远不会使用IDR之前的图像的数据来解码。
- 一个序列就是一段内容差异不太大的图像编码后生成的一串数据流
- 当运动变化比较少时,一个序列可以很长,因为运动变化少就代表图像画面的内容变动很小,所以就可以编一个I帧,然后一直P帧、B帧了。
- 当运动变化多时,可能一个序列就比较短了,比如就包含一个I帧和3、4个P帧。
- 在视频编码序列中,GOP即Group of picture(图像组),指两个I帧之间的距离
码率: 图片进行压缩后每秒显示的数据量。
帧率: 每秒显示的图片数。影响画面流畅度,与画面流畅度成正比:帧率越大,画面越流畅;帧率越小,画面越有跳动感。(由于人类眼睛的特殊生理结构,如果所看画面之帧率高于16的时候,就会认为是连贯的,此现象称之为视觉暂留。并且当帧速达到一定数值后,再增长的话,人眼也不容易察觉到有明显的流畅度提升了。)
分辨率:(矩形)图片的长度和宽度,即图片的尺寸
压缩前的每秒数据量:帧率X分辨率(单位应该是若干个字节)
压缩比:压缩前的每秒数据量/码率 (对于同一个视频源并采用同一种视频编码算法,则:压缩比越高,画面质量越差。)
视频文件格式:文件的后缀,比如
.wmv
,.mov
,.mp4
,.mp3
,.avi
,(主要用处:根据文件格式,系统会自动判断用什么软件打开,
注意: 随意修改文件格式,对文件的本身不会造成太大的影响,比如把avi
改成mp4
,文件还是avi.
)视频封装格式:一种储存视频信息的容器,流式封装可以有
TS
、FLV
等,索引式的封装有MP4
,MOV
,AVI
等,(主要作用:一个视频文件往往会包含图像和音频,还有一些配置信息(如图像和音频的关联,如何解码它们等):这些内容需要按照一定的规则组织、封装起来.
注意:会发现封装格式跟文件格式一样,因为一般视频文件格式的后缀名即采用相应的视频封装格式的名称,所以视频文件格式就是视频封装格式。)视频封装格式和视频压缩编码标准:就好像项目工程和编程语言,封装格式就是一个项目的工程,视频编码方式就是编程语言,一个项目工程可以用不同语言开发。
视频编码框架
-
FFmpeg
:是一个跨平台的开源视频框架,能实现如视频编码,解码,转码,串流,播放等丰富的功能。其支持的视频格式以及播放协议非常丰富,几乎包含了所有音视频编解码、封装格式以及播放协议。- -Libswresample:可以对音频进行重采样,rematrixing 以及转换采样格式等操 作。
- -Libavcodec:提供了一个通用的编解码框架,包含了许多视频,音频,字幕流 等编码/解码器。
- -Libavformat:用于对视频进行封装/解封装。
- -Libavutil:包含一些共用的函数,如随机数生成,数据结构,数学运算等。
- -Libpostproc:用于进行视频的一些后期处理。
- -Libswscale:用于视频图像缩放,颜色空间转换等。
- -Libavfilter:提供滤镜功能。
-
X264
:把视频原数据YUV编码压缩成H.264格式 -
VideoToolbox
:苹果自带的视频硬解码和硬编码API,但是在iOS8之后才开放。 -
AudioToolbox
:苹果自带的音频硬解码和硬编码API
编码的常见流程
- 在进行当前信号编码时,编码器首先会产生对当前信号做预测的信号,称作预测信号(predicted signal)
- 预测的方式:
- 时间上的预测(interprediction),亦即使用先前帧的信号做预测
- 空间上的预测 (intra prediction),亦即使用同一张帧之中相邻像素的信号做预测
- 得到预测信号后,编码器会将当前信号与预测信号相减得到残余信号(residual signal),并只对残余信号进行编码
- 如此一来,可以去除一部份时间上或是空间上的冗余信息
- 编码器并不会直接对残余信号进行编码,而是先将残余信号经过变换(通常为离散余弦变换)然后量化以进一步去除空间上和感知上的冗余信息
- 量化后得到的量化系数会再透过熵编码,去除统计上的冗余信息
视频编码技术
-
视频压缩编码标准:对视频进行压缩(视频编码)或者解压缩(视频解码)的编码技术,比如
MPEG
,H.264
,这些视频编码技术是压缩编码视频的- 主要作用:是将视频像素数据压缩成为视频码流,从而降低视频的数据量。如果视频不经过压缩编码的话,体积通常是非常大的,一部电影可能就要上百G的空间。
- 注意:最影响视频质量的是其视频编码数据和音频编码数据,跟封装格式没有多大关系
MPEG
:一种视频压缩方式,它采用了帧间压缩,仅存储连续帧之间有差别的地方 ,从而达到较大的压缩比H.264/AVC
:
一种视频压缩方式,采用事先预测和与MPEG
中的P-B帧一样的帧预测方法压缩,它可以根据需要产生适合网络情况传输的视频流,还有更高的压缩比,有更好的图象质量-
在H264协议里定义了三种帧
- I帧:完整编码的帧叫I帧
- P帧:参考之前的I帧生成的只包含差异部分编码的帧叫P帧
- B帧:参考前后的帧编码的帧叫B帧
-
H264采用的核心算法是帧内压缩和帧间压缩
- 帧内压缩是生成I帧的算法
- 帧间压缩是生成B帧和P帧的算法
-
H264的压缩方法:
- 分组: 把几帧图像分为一组(GOP,也就是一个序列),为防止运动变化,帧数不宜取多
- 定义帧: 将每组内各帧图像定义为三种类型,即I帧、B帧和P帧;
- 预测帧: 以I帧做为基础帧,以I帧预测P帧,再由I帧和P帧预测B帧;
- 数据传输: 最后将I帧数据与预测的差值信息进行存储和传输。
注意1:如果是从单个画面清晰度比较,
MPEG4
有优势;从动作连贯性上的清晰度,H.264
有优势注意2:由于264的算法更加复杂,程序实现烦琐,运行它需要更多的处理器和内存资源。因此,运行
264
对系统要求是比较高的。注意3:由于264的实现更加灵活,它把一些实现留给了厂商自己去实现,虽然这样给实现带来了很多好处,但是不同产品之间互通成了很大的问题,造成了通过A公司的编码器编出的数据,必须通过A公司的解码器去解这样尴尬的事情
-
H.265/HEVC
:一种视频压缩方式,基于H.264
,保留原来的某些技术,同时对一些相关的技术加以改进,以改善码流、编码质量、延时和算法复杂度之间的关系,达到最优化设置。-
H.265
是一种更为高效的编码标准,能够在同等画质效果下将内容的体积压缩得更小,传输时更快更省带宽
-
I-frames帧
:(关键帧)保留一副完整的画面,解码时只需要本帧数据就可以完成(这些帧都是一些单独的帧或关键帧,包含创建完整图片 需要的所有数据。每个GOP都正好有一个I-frames。由于它是独立帧,其尺寸最大,但也是解压最快的)
*P-frames帧
:(差别帧,预测帧)保留这一帧跟之前帧的差别,解码时需要用之前缓存的画面叠加上本帧定义的差别,生成最终画面。(P帧没有完整画面数据,只有与前一帧的画面差别的数据)B-frames帧
:(双向差别帧)保留的是本帧与前后帧的差别,解码B帧,不仅要取得之前的缓存画面,还要解码之后的画面,通过前后画面的与本帧数据的叠加取得最终的画面。B帧压缩率高,但是解码时CPU会比较累帧内(Intraframe)压缩
:当压缩一帧图像时,仅考虑本帧的数据而不考虑相邻帧之间的冗余信息,帧内一般采用有损压缩算法(帧内压缩通过消除包含在每个独立视频帧内的色彩及结构中的冗余信息来进行压缩,因此可在不降低图片质量的情况下尽可能缩小尺寸,这类压缩同JEPG压缩原理类似。但通常用于对原始图片的一部分进行处理以生成极高质量的照片。通过这一过程创建的帧称为I-frames)帧间(Interframe)压缩
:时间压缩(Temporal compression),它通过比较时间轴上不同帧之间的数据进行压缩。帧间压缩一般是无损的(在帧内压缩中,很多帧被组合在一起作为一组图片(简称GOP),对于GOP所存在的时间维度的冗余可以被消除。如果想象视频文件中的经典场景,就会有一些特定运动元素的概念,比如行驶的汽车或街上走路的行人,场景的背景环境通常是固定的,固定的背景环境就代表一个时间维度上的冗余,这个冗余就可以通过压缩方式消除)
编码方式
-
编码的方式有两种:
- 硬编码:使用非CPU进行编码,如显卡GPU、专用的DSP、FPGA、ASIC芯片等
- 软编码:使用CPU进行编码,软编码通常使用:ffmpeg+x264
- ffmpeg:是一套开源的、用于对音视频进行编码&解码&转化计算机程序
- x264:x264是一种免费的、开源的、具有更优秀算法的H.264/MPEG-4 AVC视频压缩编码方式
-
对比:(没有对比就没有伤害)
- 软编码:实现直接、简单,参数调整方便,升级易,但CPU负载重,性能较硬编码低
- 性能高,对CPU没有压力,但是对其他硬件要求较高(如GPU等)
-
iOS中编码方式:
- 在iOS8之前,苹果并没有开放硬编码的接口,所以只能采用ffpeng+x624进行软编码
- 在iOS8之后,苹果开放了接口,并且封装了VideoToolBox&AudioToolbox两个框架,分别用于对视频&音频进行硬编码
*muxing(合成)
:将视频流、音频流甚至是字幕流封装到一个文件中(容器格式(FLV
,TS
)),作为一个信号进行传输。